Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
M
MBetterc
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Mbetter
MBetterc
Commits
0d4bd057
Commit
0d4bd057
authored
Nov 25, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
NEXT_MATCH fixed
parent
549596de
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
280 additions
and
172 deletions
+280
-172
games_thread.py
mbetterclient/core/games_thread.py
+4
-8
match_timer.py
mbetterclient/core/match_timer.py
+15
-7
player.py
mbetterclient/qt_player/player.py
+26
-14
match.html
mbetterclient/qt_player/templates/match.html
+62
-34
results.html
mbetterclient/qt_player/templates/results.html
+130
-102
overlay.js
mbetterclient/web_dashboard/static/overlay.js
+43
-7
No files found.
mbetterclient/core/games_thread.py
View file @
0d4bd057
...
...
@@ -1775,8 +1775,8 @@ class GamesThread(ThreadedComponent):
# Send MATCH_DONE message with result
self
.
_send_match_done
(
fixture_id
,
match_id
,
result
)
# Send
START_INTRO message to start the next match cycle
self
.
_
dispatch_start_intro
(
fixture
_id
)
# Send
NEXT_MATCH message to advance to next match
self
.
_
send_next_match
(
fixture_id
,
match
_id
)
except
Exception
as
e
:
logger
.
error
(
f
"Failed to handle PLAY_VIDEO_RESULTS_DONE message: {e}"
)
...
...
@@ -1818,12 +1818,8 @@ class GamesThread(ThreadedComponent):
finally
:
session
.
close
()
# Wait 2 seconds then send NEXT_MATCH
import
time
time
.
sleep
(
2
)
# Send NEXT_MATCH message
self
.
_send_next_match
(
fixture_id
,
match_id
)
# NEXT_MATCH is now sent immediately in _handle_play_video_result_done
# to avoid the 2-second delay and ensure proper sequencing
except
Exception
as
e
:
logger
.
error
(
f
"Failed to handle MATCH_DONE message: {e}"
)
...
...
mbetterclient/core/match_timer.py
View file @
0d4bd057
...
...
@@ -243,16 +243,24 @@ class MatchTimerComponent(ThreadedComponent):
logger
.
info
(
f
"Received NEXT_MATCH message for fixture {fixture_id}, match {match_id}"
)
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
()
if
match_info
:
logger
.
info
(
f
"Started next match {match_info['match_id']} in fixture {match_info['fixture_id']}"
)
# Reset timer for next interval
match_interval
=
self
.
_get_match_interval
()
self
.
_start_timer
(
match_interval
*
60
,
match_info
[
'fixture_id'
])
logger
.
info
(
f
"Timer restarted for {match_interval} minute interval"
)
logger
.
info
(
f
"Prepared next match {match_info['match_id']} in fixture {match_info['fixture_id']}"
)
# Update timer with correct fixture_id if different
if
match_info
[
'fixture_id'
]
!=
fixture_id
:
with
self
.
_timer_lock
:
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
:
logger
.
info
(
"No more matches to start, stopping timer"
)
self
.
_stop_timer
()
...
...
mbetterclient/qt_player/player.py
View file @
0d4bd057
...
...
@@ -118,35 +118,41 @@ class OverlayWebChannel(QObject):
"""Send data update to JavaScript (thread-safe)"""
# Validate data before sending to prevent null emissions
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
# Debug original data before cleaning
logger
.
debug
(
f
"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 received data: {data}, type: {type(data)}"
)
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
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
:
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
# Debug what data is being sent to JavaScript
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
.
debug
(
f
"
Data type: {type(cleaned_data)}, Data is dict: {isinstance(cleaned_data, dict)}"
)
logger
.
info
(
f
"RESULTS DEBUG:
OverlayWebChannel sending to JavaScript: {len(cleaned_data)} items with keys: {data_keys}"
)
logger
.
info
(
f
"RESULTS DEBUG:
Data type: {type(cleaned_data)}, Data is dict: {isinstance(cleaned_data, dict)}"
)
with
QMutexLocker
(
self
.
mutex
):
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
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
)
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
:
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
]:
"""Clean data by removing null/undefined values before sending to JavaScript"""
...
...
@@ -204,13 +210,19 @@ class OverlayWebChannel(QObject):
def
getCurrentData
(
self
)
->
str
:
"""Provide current overlay data to JavaScript via WebChannel"""
try
:
logger
.
debug
(
"OverlayWebChannel:
getCurrentData called"
)
logger
.
info
(
"RESULTS DEBUG: OverlayWebChannel
getCurrentData called"
)
# Return current overlay data
current_data
=
dict
(
self
.
overlay_data
)
logger
.
debug
(
f
"OverlayWebChannel: Returning current data: {current_data}"
)
return
json
.
dumps
(
current_data
)
logger
.
info
(
f
"RESULTS DEBUG: Current overlay_data keys: {list(current_data.keys())}"
)
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
:
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
({})
@
pyqtSlot
(
result
=
str
)
...
...
mbetterclient/qt_player/templates/match.html
View file @
0d4bd057
...
...
@@ -634,25 +634,37 @@
// Handle timer updates from match_timer
const
timerData
=
data
.
timer_update
;
if
(
timerData
.
running
&&
timerData
.
remaining_seconds
!==
undefined
)
{
// Format remaining time
const
minutes
=
Math
.
floor
(
timerData
.
remaining_seconds
/
60
);
const
seconds
=
timerData
.
remaining_seconds
%
60
;
const
timeString
=
`
${
minutes
.
toString
().
padStart
(
2
,
'0'
)}
:
${
seconds
.
toString
().
padStart
(
2
,
'0'
)}
`
;
// Clear any existing countdown
if
(
countdownInterval
)
{
clearInterval
(
countdownInterval
);
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'
);
if
(
countdownTimer
)
{
countdownTimer
.
textContent
=
timeString
;
countdownTimer
.
className
=
'countdown-timer'
;
countdownTimer
.
style
.
display
=
'block'
;
// Add warning/urgent classes based on time remaining
if
(
timerData
.
remaining_seconds
<=
60
)
{
// 1 minute
countdownTimer
.
className
=
'countdown-timer urgent'
;
}
else
if
(
timerData
.
remaining_seconds
<=
300
)
{
// 5 minutes
countdownTimer
.
className
=
'countdown-timer warning'
;
}
else
{
countdownTimer
.
className
=
'countdown-timer'
;
}
if
(
nextMatchInfo
)
nextMatchInfo
.
style
.
display
=
'none'
;
if
(
countdownTimer
)
countdownTimer
.
style
.
display
=
'none'
;
// Clear countdown interval
if
(
countdownInterval
)
{
clearInterval
(
countdownInterval
);
countdownInterval
=
null
;
}
}
}
...
...
@@ -661,25 +673,37 @@
// Handle timer updates from match_timer
const
timerData
=
data
.
timer_update
;
if
(
timerData
.
running
&&
timerData
.
remaining_seconds
!==
undefined
)
{
// Format remaining time
const
minutes
=
Math
.
floor
(
timerData
.
remaining_seconds
/
60
);
const
seconds
=
timerData
.
remaining_seconds
%
60
;
const
timeString
=
`
${
minutes
.
toString
().
padStart
(
2
,
'0'
)}
:
${
seconds
.
toString
().
padStart
(
2
,
'0'
)}
`
;
// Clear any existing countdown
if
(
countdownInterval
)
{
clearInterval
(
countdownInterval
);
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'
);
if
(
countdownTimer
)
{
countdownTimer
.
textContent
=
timeString
;
countdownTimer
.
className
=
'countdown-timer'
;
countdownTimer
.
style
.
display
=
'block'
;
// Add warning/urgent classes based on time remaining
if
(
timerData
.
remaining_seconds
<=
60
)
{
// 1 minute
countdownTimer
.
className
=
'countdown-timer urgent'
;
}
else
if
(
timerData
.
remaining_seconds
<=
300
)
{
// 5 minutes
countdownTimer
.
className
=
'countdown-timer warning'
;
}
else
{
countdownTimer
.
className
=
'countdown-timer'
;
}
if
(
nextMatchInfo
)
nextMatchInfo
.
style
.
display
=
'none'
;
if
(
countdownTimer
)
countdownTimer
.
style
.
display
=
'none'
;
// Clear countdown interval
if
(
countdownInterval
)
{
clearInterval
(
countdownInterval
);
countdownInterval
=
null
;
}
}
}
...
...
@@ -1138,6 +1162,10 @@
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
debugTime
(
'Fetching fixture data from WebChannel'
);
fetchFixtureData
();
...
...
mbetterclient/qt_player/templates/results.html
View file @
0d4bd057
...
...
@@ -4,6 +4,7 @@
<meta
charset=
"utf-8"
>
<title>
Results Overlay
</title>
<script
src=
"qrc:///qtwebchannel/qwebchannel.js"
></script>
<script
src=
"overlay://overlay.js"
></script>
<style>
*
{
margin
:
0
;
...
...
@@ -772,6 +773,8 @@
let
videoStartTime
=
null
;
let
contentDelayTimer
=
null
;
let
resultsTimer
=
null
;
let
lastPositionLogTime
=
0
;
const
POSITION_LOG_THROTTLE_MS
=
500
;
// Throttle position logs to max 1 per 500ms
// Define showLoadingState for compatibility (results template doesn't use loading state)
function
showLoadingState
()
{
...
...
@@ -797,13 +800,21 @@
// Function to update overlay data (called by Qt WebChannel)
function
updateOverlayData
(
data
)
{
console
.
log
(
'
DEBUG
: updateOverlayData called with data:'
,
data
);
console
.
log
(
'
RESULTS TEMPLATE
: updateOverlayData called with data:'
,
data
);
overlayData
=
data
||
{};
// Only update if we have valid data
if
(
data
&&
(
data
.
outcome
||
data
.
result
))
{
let
result
=
data
.
outcome
||
data
.
result
;
console
.
log
(
'DEBUG: Processing valid result:'
,
result
);
console
.
log
(
'RESULTS TEMPLATE: Processing valid result:'
,
result
);
// Check if this is the same data we already processed (prevent duplicate processing)
const
dataHash
=
JSON
.
stringify
(
data
);
if
(
window
.
lastProcessedDataHash
===
dataHash
)
{
console
.
log
(
'RESULTS TEMPLATE: Duplicate data received, ignoring'
);
return
;
}
window
.
lastProcessedDataHash
=
dataHash
;
// Always treat the main result as the primary outcome
currentMainResult
=
result
;
...
...
@@ -811,7 +822,7 @@
// Check if under/over result is provided separately
if
(
data
.
under_over_result
)
{
currentUnderOverResult
=
data
.
under_over_result
;
console
.
log
(
'
DEBUG
: Under/over result provided separately:'
,
currentUnderOverResult
);
console
.
log
(
'
RESULTS TEMPLATE
: Under/over result provided separately:'
,
currentUnderOverResult
);
}
else
{
// Fallback: determine if main result is under/over
if
(
result
===
'UNDER'
||
result
===
'OVER'
)
{
...
...
@@ -824,20 +835,20 @@
if
(
data
.
match
)
{
currentMatch
=
data
.
match
;
console
.
log
(
'
DEBUG
: Match data received:'
,
data
.
match
);
console
.
log
(
'
RESULTS TEMPLATE
: Match data received:'
,
data
.
match
);
}
if
(
data
.
match_id
)
{
console
.
log
(
'
DEBUG
: Match ID received:'
,
data
.
match_id
);
console
.
log
(
'
RESULTS TEMPLATE
: Match ID received:'
,
data
.
match_id
);
// Fetch winning outcomes for this match
fetchWinningOutcomes
(
data
.
match_id
);
// Check if results have already been shown for this match (handles overlay reloads)
const
resultsShownKey
=
'results_shown_'
+
data
.
match_id
;
const
alreadyShown
=
sessionStorage
.
getItem
(
resultsShownKey
)
===
'true'
;
console
.
log
(
'
DEBUG
: Results already shown for match?'
,
alreadyShown
);
console
.
log
(
'
RESULTS TEMPLATE
: Results already shown for match?'
,
alreadyShown
);
if
(
alreadyShown
)
{
console
.
log
(
'
DEBUG
: Results already shown for this match, displaying immediately'
);
console
.
log
(
'
RESULTS TEMPLATE
: Results already shown for this match, displaying immediately'
);
contentVisible
=
true
;
showResultsPanel
();
showResultsContent
();
...
...
@@ -846,11 +857,11 @@
}
// Prepare data and start 5-second timer to show results
console
.
log
(
'
DEBUG
: Results data received, preparing animation data'
);
console
.
log
(
'
RESULTS TEMPLATE
: Results data received, preparing animation data'
);
prepareResultsAnimation
();
}
else
{
console
.
log
(
'
DEBUG
: No valid data received, showing loading state'
);
console
.
log
(
'
RESULTS TEMPLATE
: No valid data received, showing loading state'
);
// No valid data, show loading state
showLoadingState
();
}
...
...
@@ -870,38 +881,43 @@
// Update winning bets display
updateWinningBetsDisplay
();
// Show
results
after 5 seconds from data receipt
// Show
blue background
after 5 seconds from data receipt
setTimeout
(()
=>
{
if
(
!
contentVisible
)
{
contentVisible
=
true
;
console
.
log
(
'Showing results after 5 seconds from data received'
);
console
.
log
(
'RESULTS TEMPLATE: Showing blue background after 5 seconds from data received'
);
// Mark results as shown in sessionStorage
if
(
overlayData
&&
overlayData
.
match_id
)
{
sessionStorage
.
setItem
(
'results_shown_'
+
overlayData
.
match_id
,
'true'
);
}
showResultsPanel
();
showResultsContent
();
showResultsPanel
();
// Show blue background
// Show data immediately after background appears
setTimeout
(()
=>
{
contentVisible
=
true
;
console
.
log
(
'RESULTS TEMPLATE: Showing data immediately after background'
);
showResultsContent
();
},
100
);
// Small delay to ensure background is visible first
}
},
5000
);
}
// Fetch winning outcomes for the match
function
fetchWinningOutcomes
(
matchId
)
{
console
.
log
(
'
DEBUG
: fetchWinningOutcomes called for match:'
,
matchId
);
console
.
log
(
'
RESULTS TEMPLATE
: fetchWinningOutcomes called for match:'
,
matchId
);
// Use Qt WebChannel to request winning outcomes data
if
(
window
.
overlay
&&
window
.
overlay
.
getWinningOutcomes
)
{
console
.
log
(
'
DEBUG
: Qt WebChannel available, requesting winning outcomes'
);
console
.
log
(
'
RESULTS TEMPLATE
: Qt WebChannel available, requesting winning outcomes'
);
try
{
const
outcomesJson
=
window
.
overlay
.
getWinningOutcomes
(
matchId
);
const
outcomesData
=
JSON
.
parse
(
outcomesJson
);
console
.
log
(
'
DEBUG
: Received winning outcomes:'
,
outcomesData
);
console
.
log
(
'
RESULTS TEMPLATE
: Received winning outcomes:'
,
outcomesData
);
winningOutcomes
=
outcomesData
||
[];
updateWinningBetsDisplay
();
}
catch
(
error
)
{
console
.
error
(
'
DEBUG
: Failed to get winning outcomes:'
,
error
);
console
.
error
(
'
RESULTS TEMPLATE
: Failed to get winning outcomes:'
,
error
);
// Fallback: show sample data for testing
winningOutcomes
=
[
{
outcome
:
'WIN1'
,
amount
:
125.00
},
...
...
@@ -911,7 +927,7 @@
updateWinningBetsDisplay
();
}
}
else
{
console
.
warn
(
'
DEBUG
: Qt WebChannel not available for fetching winning outcomes'
);
console
.
warn
(
'
RESULTS TEMPLATE
: Qt WebChannel not available for fetching winning outcomes'
);
// Fallback: show sample data for testing
winningOutcomes
=
[
{
outcome
:
'WIN1'
,
amount
:
125.00
},
...
...
@@ -924,38 +940,51 @@
// Show results panel with fade-in animation
function
showResultsPanel
()
{
console
.
log
(
'
DEBUG
: showResultsPanel called'
);
console
.
log
(
'
RESULTS TEMPLATE
: showResultsPanel called'
);
const
resultsPanel
=
document
.
getElementById
(
'resultsPanel'
);
if
(
resultsPanel
)
{
console
.
log
(
'
DEBUG
: Adding visible class to results panel'
);
console
.
log
(
'
RESULTS TEMPLATE
: Adding visible class to results panel'
);
resultsPanel
.
classList
.
add
(
'visible'
);
}
else
{
console
.
log
(
'
DEBUG
: ERROR - resultsPanel element not found'
);
console
.
log
(
'
RESULTS TEMPLATE
: ERROR - resultsPanel element not found'
);
}
}
// Show results content with animation after delay
function
showResultsContent
()
{
console
.
log
(
'
DEBUG
: showResultsContent called'
);
console
.
log
(
'
RESULTS TEMPLATE
: showResultsContent called'
);
const
resultsContent
=
document
.
getElementById
(
'resultsContent'
);
if
(
resultsContent
)
{
console
.
log
(
'
DEBUG
: Adding visible class to results content'
);
console
.
log
(
'
RESULTS TEMPLATE
: Adding visible class to results content'
);
resultsContent
.
classList
.
add
(
'visible'
);
}
else
{
console
.
log
(
'
DEBUG
: ERROR - resultsContent element not found'
);
console
.
log
(
'
RESULTS TEMPLATE
: ERROR - resultsContent element not found'
);
}
}
// Handle video position changes (for logging/debugging purposes)
function
handlePositionChange
(
position
,
duration
)
{
const
currentTime
=
Date
.
now
();
// Check if video has started playing (position > 0)
if
(
position
>
0
&&
!
videoStarted
)
{
videoStarted
=
true
;
console
.
log
(
'Video started playing at position:'
,
position
);
console
.
log
(
'
RESULTS TEMPLATE:
Video started playing at position:'
,
position
);
}
// Log position for debugging
console
.
log
(
'Video position:'
,
position
,
'duration:'
,
duration
);
// Check if we've reached 5 seconds and should show results
if
(
position
>=
5
&&
!
contentVisible
&&
overlayData
&&
(
overlayData
.
outcome
||
overlayData
.
result
))
{
console
.
log
(
'RESULTS TEMPLATE: Video reached 5 seconds, showing results'
);
contentVisible
=
true
;
showResultsPanel
();
showResultsContent
();
}
// Throttle position logging to reduce message bus traffic
if
(
currentTime
-
lastPositionLogTime
>=
POSITION_LOG_THROTTLE_MS
)
{
console
.
log
(
'RESULTS TEMPLATE: Video position:'
,
position
,
'duration:'
,
duration
);
lastPositionLogTime
=
currentTime
;
}
}
// Update fighters display
...
...
@@ -1074,21 +1103,27 @@
}
}
// Request current data from backend (now handled by WebChannel signals)
function
requestCurrentData
()
{
console
.
log
(
'RESULTS TEMPLATE: requestCurrentData called - data is received via WebChannel signals'
);
// Data is handled by dataUpdated signal connection, no need to manually request
}
// Initialize when DOM is loaded
document
.
addEventListener
(
'DOMContentLoaded'
,
function
()
{
console
.
log
(
'
DEBUG: Results overlay
DOM loaded and initialized'
);
console
.
log
(
'
DEBUG
: sessionStorage available:'
,
typeof
sessionStorage
!==
'undefined'
);
console
.
log
(
'
RESULTS TEMPLATE:
DOM loaded and initialized'
);
console
.
log
(
'
RESULTS TEMPLATE
: sessionStorage available:'
,
typeof
sessionStorage
!==
'undefined'
);
// Setup WebChannel communication
// Setup WebChannel communication
(includes data polling)
setupWebChannel
();
// Panel and content will be shown after 5 seconds when video starts playing
console
.
log
(
'
DEBUG: Waiting for results data to be received
'
);
console
.
log
(
'
RESULTS TEMPLATE: Waiting for results data to be received via WebChannel signals
'
);
// Fallback: show test results after
5 seconds if no data received
// Fallback: show test results after
10 seconds if no data received via signals
setTimeout
(()
=>
{
if
(
!
contentVisible
)
{
console
.
log
(
'
DEBUG: Fallback - No data received after 5
seconds, showing test results'
);
console
.
log
(
'
RESULTS TEMPLATE: Fallback - No data received after 10
seconds, showing test results'
);
// Set test data
currentMainResult
=
'WIN1'
;
currentUnderOverResult
=
'OVER'
;
...
...
@@ -1104,78 +1139,71 @@
updateCombinedResultDisplay
();
updateWinningBetsDisplay
();
}
},
5
000
);
},
10
000
);
});
// Setup WebChannel communication (
similar to fixtures.htm
l)
// Setup WebChannel communication (
wait for overlay.js to set up WebChanne
l)
function
setupWebChannel
()
{
// Check if WebChannel is already set up by overlay.js
if
(
window
.
overlay
)
{
console
.
log
(
'DEBUG: WebChannel already set up by overlay.js'
);
// Test WebChannel
if
(
window
.
overlay
&&
window
.
overlay
.
log
)
{
window
.
overlay
.
log
(
'TEST: WebChannel connection successful'
);
}
console
.
log
(
'RESULTS TEMPLATE: Waiting for overlay.js WebChannel to be ready...'
);
// Listen for data updates from Python
if
(
window
.
overlay
.
dataUpdated
)
{
window
.
overlay
.
dataUpdated
.
connect
(
function
(
data
)
{
console
.
log
(
'DEBUG: Received data update from Python:'
,
data
);
updateOverlayData
(
data
);
});
}
// Connect positionChanged signal
if
(
window
.
overlay
.
positionChanged
)
{
console
.
log
(
'DEBUG: Connecting positionChanged signal'
);
window
.
overlay
.
positionChanged
.
connect
(
function
(
position
,
duration
)
{
if
(
position
!==
null
&&
duration
!==
null
)
{
handlePositionChange
(
position
,
duration
);
}
else
{
console
.
warn
(
'DEBUG: positionChanged signal received null/undefined parameters'
);
}
});
// Set up global callback for dataUpdated signal (called by overlay.js)
window
.
onDataUpdated
=
function
(
data
)
{
console
.
log
(
'RESULTS TEMPLATE: onDataUpdated callback called with:'
,
data
);
if
(
data
!==
null
&&
data
!==
undefined
)
{
updateOverlayData
(
data
);
}
else
{
console
.
warn
(
'RESULTS TEMPLATE: onDataUpdated callback received null/undefined data'
);
}
return
;
}
// Fallback: setup WebChannel if overlay.js didn't do it
if
(
typeof
qt
!==
'undefined'
&&
qt
.
webChannelTransport
)
{
try
{
new
QWebChannel
(
qt
.
webChannelTransport
,
function
(
channel
)
{
console
.
log
(
'DEBUG: WebChannel connected successfully (fallback)'
);
// Connect to overlay object
window
.
overlay
=
channel
.
objects
.
overlay
;
// Listen for data updates from Python
if
(
window
.
overlay
&&
window
.
overlay
.
dataUpdated
)
{
window
.
overlay
.
dataUpdated
.
connect
(
function
(
data
)
{
console
.
log
(
'DEBUG: Received data update from Python:'
,
data
);
updateOverlayData
(
data
);
});
}
};
// Wait for overlay.js to set up the WebChannel and overlay object
const
checkOverlayReady
=
()
=>
{
if
(
window
.
overlay
&&
window
.
overlayManager
&&
window
.
overlayManager
.
webChannelReady
)
{
console
.
log
(
'RESULTS TEMPLATE: overlay.js WebChannel ready'
);
// Connect positionChanged signal if available
if
(
window
.
overlay
.
positionChanged
)
{
console
.
log
(
'RESULTS TEMPLATE: Connecting positionChanged signal'
);
window
.
overlay
.
positionChanged
.
connect
(
function
(
position
,
duration
)
{
if
(
position
!==
null
&&
duration
!==
null
)
{
handlePositionChange
(
position
,
duration
);
}
else
{
console
.
warn
(
'RESULTS TEMPLATE: positionChanged signal received null/undefined parameters'
);
}
});
}
// Connect positionChanged signal
if
(
window
.
overlay
.
positionChanged
)
{
console
.
log
(
'DEBUG: Connecting positionChanged signal'
);
window
.
overlay
.
positionChanged
.
connect
(
function
(
position
,
duration
)
{
if
(
position
!==
null
&&
duration
!==
null
)
{
handlePositionChange
(
position
,
duration
);
// Try to get current data immediately when WebChannel is ready
console
.
log
(
'RESULTS TEMPLATE: Attempting to get current data from WebChannel'
);
try
{
if
(
window
.
overlay
&&
window
.
overlay
.
getCurrentData
)
{
const
currentDataJson
=
window
.
overlay
.
getCurrentData
();
console
.
log
(
'RESULTS TEMPLATE: Got current data JSON:'
,
currentDataJson
);
if
(
currentDataJson
)
{
const
currentData
=
JSON
.
parse
(
currentDataJson
);
console
.
log
(
'RESULTS TEMPLATE: Parsed current data:'
,
currentData
);
if
(
currentData
&&
(
currentData
.
outcome
||
currentData
.
result
))
{
console
.
log
(
'RESULTS TEMPLATE: Found valid data in current data, processing'
);
updateOverlayData
(
currentData
);
}
else
{
console
.
warn
(
'DEBUG: positionChanged signal received null/undefined parameters
'
);
console
.
log
(
'RESULTS TEMPLATE: No valid result data in current data
'
);
}
}
);
}
}
});
}
catch
(
e
)
{
console
.
log
(
'DEBUG: Failed to setup WebChannel:'
,
e
);
}
catch
(
error
)
{
console
.
error
(
'RESULTS TEMPLATE: Failed to get current data:'
,
error
);
}
console
.
log
(
'RESULTS TEMPLATE: WebChannel setup completed, signals connected'
);
}
else
{
// Keep checking until overlay.js has set up the WebChannel
setTimeout
(
checkOverlayReady
,
50
);
}
}
else
{
console
.
log
(
'DEBUG: WebChannel not available'
);
}
}
;
checkOverlayReady
();
}
// Export functions for external use
window
.
setOutcome
=
setOutcome
;
...
...
@@ -1183,15 +1211,15 @@
</script>
<!--
IMPORTANT: When creating or editing custom templates, always maintain this script tag:
qrc:///qtwebchannel/qwebchannel.js - Required for Qt WebChannel communication
IMPORTANT: When creating or editing custom templates, always maintain these script tags:
1. qrc:///qtwebchannel/qwebchannel.js - Required for Qt WebChannel communication
2. overlay://overlay.js - Required for overlay functionality and data updates
This script enables communication between the Qt application and the overlay template.
The results.html template handles its own WebChannel setup and does not use overlay.js
to avoid conflicts with the custom overlay elements.
These scripts enable communication between the Qt application and the overlay template.
The results.html template uses overlay.js for WebChannel setup and adds custom dataUpdated signal handling.
NOTE: When editing this template, never remove the qwebchannel.js script source!
NOTE: When editing this template, never remove these script sources!
The overlay:// custom scheme ensures JavaScript files work for both built-in and uploaded templates.
-->
<script
src=
"qrc:///qtwebchannel/qwebchannel.js"
></script>
</body>
</html>
\ No newline at end of file
mbetterclient/web_dashboard/static/overlay.js
View file @
0d4bd057
...
...
@@ -17,12 +17,12 @@ class OverlayManager {
new
QWebChannel
(
qt
.
webChannelTransport
,
(
channel
)
=>
{
// Connect to overlay object
window
.
overlay
=
channel
.
objects
.
overlay
;
// Flush any buffered console messages
if
(
window
.
flushConsoleBuffer
)
{
window
.
flushConsoleBuffer
();
}
// Connect signals if overlay object exists
if
(
window
.
overlay
)
{
// Connect positionChanged signal
...
...
@@ -35,7 +35,7 @@ class OverlayManager {
}
});
}
// Connect videoInfoChanged signal
if
(
window
.
overlay
.
videoInfoChanged
)
{
window
.
overlay
.
videoInfoChanged
.
connect
((
info
)
=>
{
...
...
@@ -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
setTimeout
(()
=>
this
.
processPendingUpdates
(),
100
);
console
.
log
(
'WebChannel connected and ready'
);
...
...
@@ -61,7 +79,7 @@ class OverlayManager {
const
channel
=
new
QtWebChannel
();
channel
.
connectTo
(
'overlay'
,
(
overlay
)
=>
{
window
.
overlay
=
overlay
;
// Connect positionChanged signal
overlay
.
positionChanged
.
connect
((
position
,
duration
)
=>
{
if
(
position
!==
null
&&
duration
!==
null
)
{
...
...
@@ -70,7 +88,7 @@ class OverlayManager {
console
.
warn
(
'positionChanged signal received null/undefined parameters, skipping'
);
}
});
// Connect videoInfoChanged signal
overlay
.
videoInfoChanged
.
connect
((
info
)
=>
{
if
(
info
&&
typeof
info
===
'object'
)
{
...
...
@@ -79,7 +97,25 @@ class OverlayManager {
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
setTimeout
(()
=>
this
.
processPendingUpdates
(),
100
);
console
.
log
(
'WebChannel connected via fallback method'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment