NEXT_MATCH fixed

parent 549596de
...@@ -1775,8 +1775,8 @@ class GamesThread(ThreadedComponent): ...@@ -1775,8 +1775,8 @@ class GamesThread(ThreadedComponent):
# Send MATCH_DONE message with result # Send MATCH_DONE message with result
self._send_match_done(fixture_id, match_id, result) self._send_match_done(fixture_id, match_id, result)
# Send START_INTRO message to start the next match cycle # Send NEXT_MATCH message to advance to next match
self._dispatch_start_intro(fixture_id) self._send_next_match(fixture_id, match_id)
except Exception as e: except Exception as e:
logger.error(f"Failed to handle PLAY_VIDEO_RESULTS_DONE message: {e}") logger.error(f"Failed to handle PLAY_VIDEO_RESULTS_DONE message: {e}")
...@@ -1818,12 +1818,8 @@ class GamesThread(ThreadedComponent): ...@@ -1818,12 +1818,8 @@ class GamesThread(ThreadedComponent):
finally: finally:
session.close() session.close()
# Wait 2 seconds then send NEXT_MATCH # NEXT_MATCH is now sent immediately in _handle_play_video_result_done
import time # to avoid the 2-second delay and ensure proper sequencing
time.sleep(2)
# Send NEXT_MATCH message
self._send_next_match(fixture_id, match_id)
except Exception as e: except Exception as e:
logger.error(f"Failed to handle MATCH_DONE message: {e}") logger.error(f"Failed to handle MATCH_DONE message: {e}")
......
...@@ -243,16 +243,24 @@ class MatchTimerComponent(ThreadedComponent): ...@@ -243,16 +243,24 @@ class MatchTimerComponent(ThreadedComponent):
logger.info(f"Received NEXT_MATCH message for fixture {fixture_id}, match {match_id}") logger.info(f"Received NEXT_MATCH message for fixture {fixture_id}, match {match_id}")
logger.info("Previous match completed - restarting timer for next interval") logger.info("Previous match completed - restarting timer for next interval")
# Find and start the next match # Start timer first to ensure countdown is visible immediately
match_interval = self._get_match_interval()
self._start_timer(match_interval * 60, fixture_id)
logger.info(f"Timer started for {match_interval} minute interval")
# Then find and start the next match
match_info = self._find_and_start_next_match() match_info = self._find_and_start_next_match()
if match_info: if match_info:
logger.info(f"Started next match {match_info['match_id']} in fixture {match_info['fixture_id']}") logger.info(f"Prepared next match {match_info['match_id']} in fixture {match_info['fixture_id']}")
# Reset timer for next interval # Update timer with correct fixture_id if different
match_interval = self._get_match_interval() if match_info['fixture_id'] != fixture_id:
self._start_timer(match_interval * 60, match_info['fixture_id']) with self._timer_lock:
logger.info(f"Timer restarted for {match_interval} minute interval") self.current_fixture_id = match_info['fixture_id']
# Send updated timer info
self._send_timer_update()
logger.info(f"Timer updated with fixture {match_info['fixture_id']}")
else: else:
logger.info("No more matches to start, stopping timer") logger.info("No more matches to start, stopping timer")
self._stop_timer() self._stop_timer()
......
...@@ -118,35 +118,41 @@ class OverlayWebChannel(QObject): ...@@ -118,35 +118,41 @@ class OverlayWebChannel(QObject):
"""Send data update to JavaScript (thread-safe)""" """Send data update to JavaScript (thread-safe)"""
# Validate data before sending to prevent null emissions # Validate data before sending to prevent null emissions
if not data: if not data:
logger.warning("send_data_update called with null/empty data, skipping") logger.warning("RESULTS DEBUG: send_data_update called with null/empty data, skipping")
return return
# Debug original data before cleaning # Debug original data before cleaning
logger.debug(f"OverlayWebChannel received data: {data}, type: {type(data)}") logger.info(f"RESULTS DEBUG: OverlayWebChannel received data: {data}, type: {type(data)}")
logger.debug(f"OverlayWebChannel data keys: {list(data.keys()) if isinstance(data, dict) else 'not dict'}") logger.info(f"RESULTS DEBUG: OverlayWebChannel data keys: {list(data.keys()) if isinstance(data, dict) else 'not dict'}")
# Check if this data contains results information
has_results_data = any(key in data for key in ['outcome', 'result', 'match', 'match_id', 'fixture_id'])
logger.info(f"RESULTS DEBUG: Data contains results info: {has_results_data}")
# Clean data to remove null/undefined values before sending to JavaScript # Clean data to remove null/undefined values before sending to JavaScript
cleaned_data = self._clean_data(data) cleaned_data = self._clean_data(data)
logger.debug(f"OverlayWebChannel cleaned data: {cleaned_data}") logger.info(f"RESULTS DEBUG: OverlayWebChannel cleaned data: {cleaned_data}")
if not cleaned_data: if not cleaned_data:
logger.debug("All data properties were null/undefined, skipping JavaScript update") logger.info("RESULTS DEBUG: All data properties were null/undefined, skipping JavaScript update")
return return
# Debug what data is being sent to JavaScript # Debug what data is being sent to JavaScript
data_keys = list(cleaned_data.keys()) if isinstance(cleaned_data, dict) else [] data_keys = list(cleaned_data.keys()) if isinstance(cleaned_data, dict) else []
logger.debug(f"OverlayWebChannel sending to JavaScript: {len(cleaned_data)} items with keys: {data_keys}") logger.info(f"RESULTS DEBUG: OverlayWebChannel sending to JavaScript: {len(cleaned_data)} items with keys: {data_keys}")
logger.debug(f"Data type: {type(cleaned_data)}, Data is dict: {isinstance(cleaned_data, dict)}") logger.info(f"RESULTS DEBUG: Data type: {type(cleaned_data)}, Data is dict: {isinstance(cleaned_data, dict)}")
with QMutexLocker(self.mutex): with QMutexLocker(self.mutex):
self.overlay_data.update(cleaned_data) self.overlay_data.update(cleaned_data)
logger.info(f"RESULTS DEBUG: Updated overlay_data, now contains: {list(self.overlay_data.keys())}")
# Add additional validation just before emit # Add additional validation just before emit
if cleaned_data and isinstance(cleaned_data, dict) and any(v is not None for v in cleaned_data.values()): if cleaned_data and isinstance(cleaned_data, dict) and any(v is not None for v in cleaned_data.values()):
logger.debug(f"OverlayWebChannel emitting dataUpdated signal with: {cleaned_data}") logger.info(f"RESULTS DEBUG: OverlayWebChannel emitting dataUpdated signal with: {cleaned_data}")
self.dataUpdated.emit(cleaned_data) self.dataUpdated.emit(cleaned_data)
data_keys = list(cleaned_data.keys()) if isinstance(cleaned_data, dict) else [] data_keys = list(cleaned_data.keys()) if isinstance(cleaned_data, dict) else []
logger.debug(f"Signal emitted successfully with {len(cleaned_data)} data items: {data_keys}") logger.info(f"RESULTS DEBUG: Signal emitted successfully with {len(cleaned_data)} data items: {data_keys}")
else: else:
logger.warning(f"Prevented emission of invalid data: {cleaned_data}") logger.warning(f"RESULTS DEBUG: Prevented emission of invalid data: {cleaned_data}")
def _clean_data(self, data: Dict[str, Any]) -> Dict[str, Any]: def _clean_data(self, data: Dict[str, Any]) -> Dict[str, Any]:
"""Clean data by removing null/undefined values before sending to JavaScript""" """Clean data by removing null/undefined values before sending to JavaScript"""
...@@ -204,13 +210,19 @@ class OverlayWebChannel(QObject): ...@@ -204,13 +210,19 @@ class OverlayWebChannel(QObject):
def getCurrentData(self) -> str: def getCurrentData(self) -> str:
"""Provide current overlay data to JavaScript via WebChannel""" """Provide current overlay data to JavaScript via WebChannel"""
try: try:
logger.debug("OverlayWebChannel: getCurrentData called") logger.info("RESULTS DEBUG: OverlayWebChannel getCurrentData called")
# Return current overlay data # Return current overlay data
current_data = dict(self.overlay_data) current_data = dict(self.overlay_data)
logger.debug(f"OverlayWebChannel: Returning current data: {current_data}") logger.info(f"RESULTS DEBUG: Current overlay_data keys: {list(current_data.keys())}")
return json.dumps(current_data) logger.info(f"RESULTS DEBUG: Current overlay_data: {current_data}")
logger.info(f"RESULTS DEBUG: Returning current data to JavaScript: {current_data}")
json_result = json.dumps(current_data)
logger.info(f"RESULTS DEBUG: JSON result length: {len(json_result)}")
return json_result
except Exception as e: except Exception as e:
logger.error(f"OverlayWebChannel: Failed to get current data: {e}") logger.error(f"RESULTS DEBUG: OverlayWebChannel Failed to get current data: {e}")
import traceback
logger.error(f"RESULTS DEBUG: Full traceback: {traceback.format_exc()}")
return json.dumps({}) return json.dumps({})
@pyqtSlot(result=str) @pyqtSlot(result=str)
......
...@@ -634,25 +634,37 @@ ...@@ -634,25 +634,37 @@
// Handle timer updates from match_timer // Handle timer updates from match_timer
const timerData = data.timer_update; const timerData = data.timer_update;
if (timerData.running && timerData.remaining_seconds !== undefined) { if (timerData.running && timerData.remaining_seconds !== undefined) {
// Format remaining time // Clear any existing countdown
const minutes = Math.floor(timerData.remaining_seconds / 60); if (countdownInterval) {
const seconds = timerData.remaining_seconds % 60; clearInterval(countdownInterval);
const timeString = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; countdownInterval = null;
}
// Set next match start time
nextMatchStartTime = new Date(Date.now() + (timerData.remaining_seconds * 1000));
// Show next match info
const nextMatchInfo = document.getElementById('nextMatchInfo');
if (nextMatchInfo) {
nextMatchInfo.textContent = `Next match starting in:`;
nextMatchInfo.style.display = 'block';
}
// Start countdown
updateCountdown();
countdownInterval = setInterval(updateCountdown, 1000);
console.log('🔍 DEBUG: Countdown started from timer update');
} else {
// No active timer, hide countdown
const nextMatchInfo = document.getElementById('nextMatchInfo');
const countdownTimer = document.getElementById('countdownTimer'); const countdownTimer = document.getElementById('countdownTimer');
if (countdownTimer) { if (nextMatchInfo) nextMatchInfo.style.display = 'none';
countdownTimer.textContent = timeString; if (countdownTimer) countdownTimer.style.display = 'none';
countdownTimer.className = 'countdown-timer';
countdownTimer.style.display = 'block'; // Clear countdown interval
if (countdownInterval) {
// Add warning/urgent classes based on time remaining clearInterval(countdownInterval);
if (timerData.remaining_seconds <= 60) { // 1 minute countdownInterval = null;
countdownTimer.className = 'countdown-timer urgent';
} else if (timerData.remaining_seconds <= 300) { // 5 minutes
countdownTimer.className = 'countdown-timer warning';
} else {
countdownTimer.className = 'countdown-timer';
}
} }
} }
} }
...@@ -661,25 +673,37 @@ ...@@ -661,25 +673,37 @@
// Handle timer updates from match_timer // Handle timer updates from match_timer
const timerData = data.timer_update; const timerData = data.timer_update;
if (timerData.running && timerData.remaining_seconds !== undefined) { if (timerData.running && timerData.remaining_seconds !== undefined) {
// Format remaining time // Clear any existing countdown
const minutes = Math.floor(timerData.remaining_seconds / 60); if (countdownInterval) {
const seconds = timerData.remaining_seconds % 60; clearInterval(countdownInterval);
const timeString = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; countdownInterval = null;
}
// Set next match start time
nextMatchStartTime = new Date(Date.now() + (timerData.remaining_seconds * 1000));
// Show next match info
const nextMatchInfo = document.getElementById('nextMatchInfo');
if (nextMatchInfo) {
nextMatchInfo.textContent = `Next match starting in:`;
nextMatchInfo.style.display = 'block';
}
// Start countdown
updateCountdown();
countdownInterval = setInterval(updateCountdown, 1000);
console.log('🔍 DEBUG: Countdown started from timer update');
} else {
// No active timer, hide countdown
const nextMatchInfo = document.getElementById('nextMatchInfo');
const countdownTimer = document.getElementById('countdownTimer'); const countdownTimer = document.getElementById('countdownTimer');
if (countdownTimer) { if (nextMatchInfo) nextMatchInfo.style.display = 'none';
countdownTimer.textContent = timeString; if (countdownTimer) countdownTimer.style.display = 'none';
countdownTimer.className = 'countdown-timer';
countdownTimer.style.display = 'block'; // Clear countdown interval
if (countdownInterval) {
// Add warning/urgent classes based on time remaining clearInterval(countdownInterval);
if (timerData.remaining_seconds <= 60) { // 1 minute countdownInterval = null;
countdownTimer.className = 'countdown-timer urgent';
} else if (timerData.remaining_seconds <= 300) { // 5 minutes
countdownTimer.className = 'countdown-timer warning';
} else {
countdownTimer.className = 'countdown-timer';
}
} }
} }
} }
...@@ -1138,6 +1162,10 @@ ...@@ -1138,6 +1162,10 @@
console.log('🔍 DEBUG: WebServerBaseUrl not received via WebChannel, proceeding with WebChannel data fetch'); console.log('🔍 DEBUG: WebServerBaseUrl not received via WebChannel, proceeding with WebChannel data fetch');
} }
// Check for timer state immediately when page loads
debugTime('Checking timer state on page load');
getTimerStateAndStartCountdown();
// Fetch fixture data directly from WebChannel // Fetch fixture data directly from WebChannel
debugTime('Fetching fixture data from WebChannel'); debugTime('Fetching fixture data from WebChannel');
fetchFixtureData(); fetchFixtureData();
......
...@@ -17,12 +17,12 @@ class OverlayManager { ...@@ -17,12 +17,12 @@ class OverlayManager {
new QWebChannel(qt.webChannelTransport, (channel) => { new QWebChannel(qt.webChannelTransport, (channel) => {
// Connect to overlay object // Connect to overlay object
window.overlay = channel.objects.overlay; window.overlay = channel.objects.overlay;
// Flush any buffered console messages // Flush any buffered console messages
if (window.flushConsoleBuffer) { if (window.flushConsoleBuffer) {
window.flushConsoleBuffer(); window.flushConsoleBuffer();
} }
// Connect signals if overlay object exists // Connect signals if overlay object exists
if (window.overlay) { if (window.overlay) {
// Connect positionChanged signal // Connect positionChanged signal
...@@ -35,7 +35,7 @@ class OverlayManager { ...@@ -35,7 +35,7 @@ class OverlayManager {
} }
}); });
} }
// Connect videoInfoChanged signal // Connect videoInfoChanged signal
if (window.overlay.videoInfoChanged) { if (window.overlay.videoInfoChanged) {
window.overlay.videoInfoChanged.connect((info) => { window.overlay.videoInfoChanged.connect((info) => {
...@@ -46,7 +46,25 @@ class OverlayManager { ...@@ -46,7 +46,25 @@ class OverlayManager {
} }
}); });
} }
// Connect dataUpdated signal for templates that need it (like results.html)
if (window.overlay.dataUpdated) {
window.overlay.dataUpdated.connect((data) => {
if (data !== null && data !== undefined) {
// Call a global callback if it exists (for results.html and other templates)
if (window.onDataUpdated) {
window.onDataUpdated(data);
}
console.log('dataUpdated signal received:', data);
} else {
console.warn('dataUpdated signal received null/undefined data');
}
});
}
// Mark WebChannel as ready
this.webChannelReady = true;
// Process pending updates after full initialization // Process pending updates after full initialization
setTimeout(() => this.processPendingUpdates(), 100); setTimeout(() => this.processPendingUpdates(), 100);
console.log('WebChannel connected and ready'); console.log('WebChannel connected and ready');
...@@ -61,7 +79,7 @@ class OverlayManager { ...@@ -61,7 +79,7 @@ class OverlayManager {
const channel = new QtWebChannel(); const channel = new QtWebChannel();
channel.connectTo('overlay', (overlay) => { channel.connectTo('overlay', (overlay) => {
window.overlay = overlay; window.overlay = overlay;
// Connect positionChanged signal // Connect positionChanged signal
overlay.positionChanged.connect((position, duration) => { overlay.positionChanged.connect((position, duration) => {
if (position !== null && duration !== null) { if (position !== null && duration !== null) {
...@@ -70,7 +88,7 @@ class OverlayManager { ...@@ -70,7 +88,7 @@ class OverlayManager {
console.warn('positionChanged signal received null/undefined parameters, skipping'); console.warn('positionChanged signal received null/undefined parameters, skipping');
} }
}); });
// Connect videoInfoChanged signal // Connect videoInfoChanged signal
overlay.videoInfoChanged.connect((info) => { overlay.videoInfoChanged.connect((info) => {
if (info && typeof info === 'object') { if (info && typeof info === 'object') {
...@@ -79,7 +97,25 @@ class OverlayManager { ...@@ -79,7 +97,25 @@ class OverlayManager {
console.warn('videoInfoChanged signal received null/undefined parameter, skipping'); console.warn('videoInfoChanged signal received null/undefined parameter, skipping');
} }
}); });
// Connect dataUpdated signal for templates that need it (like results.html)
if (overlay.dataUpdated) {
overlay.dataUpdated.connect((data) => {
if (data !== null && data !== undefined) {
// Call a global callback if it exists (for results.html and other templates)
if (window.onDataUpdated) {
window.onDataUpdated(data);
}
console.log('dataUpdated signal received:', data);
} else {
console.warn('dataUpdated signal received null/undefined data');
}
});
}
// Mark WebChannel as ready
this.webChannelReady = true;
// Process pending updates after full initialization // Process pending updates after full initialization
setTimeout(() => this.processPendingUpdates(), 100); setTimeout(() => this.processPendingUpdates(), 100);
console.log('WebChannel connected via fallback method'); console.log('WebChannel connected via fallback method');
......
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