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
5b0da3e1
Commit
5b0da3e1
authored
Nov 19, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixture template works now
parent
0632ac59
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
520 additions
and
137 deletions
+520
-137
application.py
mbetterclient/core/application.py
+6
-2
player.py
mbetterclient/qt_player/player.py
+306
-25
fixtures.html
mbetterclient/qt_player/templates/fixtures.html
+198
-107
routes.py
mbetterclient/web_dashboard/routes.py
+10
-3
No files found.
mbetterclient/core/application.py
View file @
5b0da3e1
...
@@ -595,7 +595,9 @@ class MbetterClientApplication:
...
@@ -595,7 +595,9 @@ class MbetterClientApplication:
def
_process_core_message
(
self
,
message
:
Message
):
def
_process_core_message
(
self
,
message
:
Message
):
"""Process messages received by the core component"""
"""Process messages received by the core component"""
try
:
try
:
logger
.
debug
(
f
"Core processing message: {message}"
)
# Suppress debug logging for VIDEO_PROGRESS messages to reduce log noise
if
message
.
type
!=
MessageType
.
VIDEO_PROGRESS
:
logger
.
debug
(
f
"Core processing message: {message}"
)
if
message
.
type
==
MessageType
.
SYSTEM_STATUS
:
if
message
.
type
==
MessageType
.
SYSTEM_STATUS
:
self
.
_handle_system_status
(
message
)
self
.
_handle_system_status
(
message
)
...
@@ -608,7 +610,9 @@ class MbetterClientApplication:
...
@@ -608,7 +610,9 @@ class MbetterClientApplication:
elif
message
.
type
==
MessageType
.
SYSTEM_SHUTDOWN
:
elif
message
.
type
==
MessageType
.
SYSTEM_SHUTDOWN
:
self
.
_handle_shutdown_message
(
message
)
self
.
_handle_shutdown_message
(
message
)
else
:
else
:
logger
.
debug
(
f
"Unhandled message type in core: {message.type}"
)
# Suppress debug logging for VIDEO_PROGRESS messages to reduce log noise
if
message
.
type
!=
MessageType
.
VIDEO_PROGRESS
:
logger
.
debug
(
f
"Unhandled message type in core: {message.type}"
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"Failed to process core message: {e}"
)
logger
.
error
(
f
"Failed to process core message: {e}"
)
...
...
mbetterclient/qt_player/player.py
View file @
5b0da3e1
...
@@ -47,11 +47,12 @@ logger = logging.getLogger(__name__)
...
@@ -47,11 +47,12 @@ logger = logging.getLogger(__name__)
class
OverlayWebChannel
(
QObject
):
class
OverlayWebChannel
(
QObject
):
"""QObject for WebChannel communication with overlay HTML/JS"""
"""QObject for WebChannel communication with overlay HTML/JS"""
# Signals to send data to JavaScript
# Signals to send data to JavaScript
dataUpdated
=
pyqtSignal
(
dict
)
dataUpdated
=
pyqtSignal
(
dict
)
positionChanged
=
pyqtSignal
(
float
,
float
)
# position, duration in seconds
positionChanged
=
pyqtSignal
(
float
,
float
)
# position, duration in seconds
videoInfoChanged
=
pyqtSignal
(
dict
)
videoInfoChanged
=
pyqtSignal
(
dict
)
fixtureDataUpdated
=
pyqtSignal
(
dict
)
# Signal for fixture data updates
def
__init__
(
self
):
def
__init__
(
self
):
super
()
.
__init__
()
super
()
.
__init__
()
...
@@ -178,6 +179,43 @@ class OverlayWebChannel(QObject):
...
@@ -178,6 +179,43 @@ class OverlayWebChannel(QObject):
else
:
else
:
logger
.
debug
(
"Video info contained only null/undefined values, skipping"
)
logger
.
debug
(
"Video info contained only null/undefined values, skipping"
)
def
send_fixture_data_update
(
self
,
data
:
Dict
[
str
,
Any
]):
"""Send fixture data update to JavaScript (thread-safe)"""
# Validate data before emitting
if
not
data
:
logger
.
warning
(
"send_fixture_data_update called with null/empty data, skipping"
)
return
logger
.
debug
(
f
"OverlayWebChannel sending fixture data: {data}"
)
self
.
fixtureDataUpdated
.
emit
(
data
)
@
pyqtSlot
()
def
trigger_fixtures_data_load
(
self
):
"""Slot to manually trigger fixtures data loading from JavaScript"""
try
:
logger
.
info
(
"Manual trigger of fixtures data load from JavaScript"
)
# Find the PlayerWindow and trigger fixtures data load
# This method is called from JavaScript, so we need to find the PlayerWindow
overlay_view
=
None
# Try to find the overlay view that contains this channel
# We need to traverse up to find the PlayerWindow
current_obj
=
self
.
parent
()
while
current_obj
:
if
hasattr
(
current_obj
,
'_find_player_window'
):
player_window
=
current_obj
.
_find_player_window
()
if
player_window
and
hasattr
(
player_window
,
'_send_fixtures_to_overlay'
):
logger
.
debug
(
"Found PlayerWindow, triggering fixtures data load"
)
player_window
.
_send_fixtures_to_overlay
()
return
current_obj
=
current_obj
.
parent
()
logger
.
warning
(
"Could not find PlayerWindow to trigger fixtures data load"
)
except
Exception
as
e
:
logger
.
error
(
f
"Failed to trigger fixtures data load from JavaScript: {e}"
)
class
VideoProcessingWorker
(
QRunnable
):
class
VideoProcessingWorker
(
QRunnable
):
"""Background worker for video processing tasks"""
"""Background worker for video processing tasks"""
...
@@ -419,6 +457,11 @@ class OverlayWebView(QWebEngineView):
...
@@ -419,6 +457,11 @@ class OverlayWebView(QWebEngineView):
from
PyQt6.QtCore
import
QTimer
from
PyQt6.QtCore
import
QTimer
QTimer
.
singleShot
(
100
,
lambda
:
self
.
_ensure_overlay_visibility_post_load
(
was_visible
))
QTimer
.
singleShot
(
100
,
lambda
:
self
.
_ensure_overlay_visibility_post_load
(
was_visible
))
# If fixtures template was loaded, trigger fixtures data loading
if
template_name
==
"fixtures.html"
or
template_name
==
"fixtures"
:
logger
.
info
(
"Fixtures template loaded, scheduling fixtures data load"
)
QTimer
.
singleShot
(
500
,
lambda
:
self
.
_trigger_fixtures_data_load
())
if
self
.
debug_overlay
:
if
self
.
debug_overlay
:
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Template load initiated - {template_path}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Template load initiated - {template_path}"
)
logger
.
info
(
f
"Loaded template: {template_path} (source: {template_source})"
)
logger
.
info
(
f
"Loaded template: {template_path} (source: {template_source})"
)
...
@@ -619,6 +662,51 @@ class OverlayWebView(QWebEngineView):
...
@@ -619,6 +662,51 @@ class OverlayWebView(QWebEngineView):
if
self
.
overlay_channel
:
if
self
.
overlay_channel
:
self
.
overlay_channel
.
send_video_info
(
info
)
self
.
overlay_channel
.
send_video_info
(
info
)
def
_trigger_fixtures_data_load
(
self
):
"""Trigger fixtures data loading when fixtures template is loaded"""
try
:
logger
.
info
(
"Triggering fixtures data load for fixtures template"
)
# Find the PlayerWindow by traversing up the parent hierarchy
player_window
=
self
.
_find_player_window
()
if
player_window
and
hasattr
(
player_window
,
'_send_fixtures_to_overlay'
):
logger
.
debug
(
"Calling PlayerWindow's _send_fixtures_to_overlay method"
)
player_window
.
_send_fixtures_to_overlay
()
else
:
logger
.
warning
(
"Could not find PlayerWindow with _send_fixtures_to_overlay method"
)
except
Exception
as
e
:
logger
.
error
(
f
"Failed to trigger fixtures data load: {e}"
)
def
_find_player_window
(
self
):
"""Find the PlayerWindow by traversing up the parent hierarchy"""
try
:
current
=
self
.
parent
()
while
current
:
if
hasattr
(
current
,
'_send_fixtures_to_overlay'
):
logger
.
debug
(
"Found PlayerWindow in parent hierarchy"
)
return
current
current
=
current
.
parent
()
logger
.
debug
(
"PlayerWindow not found in parent hierarchy"
)
return
None
except
Exception
as
e
:
logger
.
error
(
f
"Error finding PlayerWindow: {e}"
)
return
None
def
update_fixture_data
(
self
,
fixture_data
:
Dict
[
str
,
Any
]):
"""Update fixture data"""
if
self
.
overlay_channel
:
self
.
overlay_channel
.
send_fixture_data
(
fixture_data
)
def
_on_fixture_data_updated
(
self
,
fixture_data
:
Dict
[
str
,
Any
]):
"""Handle fixture data update signal and call JavaScript function"""
try
:
# Call the JavaScript updateFixtureData function
js_code
=
f
"updateFixtureData({json.dumps(fixture_data)});"
self
.
page
()
.
runJavaScript
(
js_code
)
logger
.
debug
(
"Called JavaScript updateFixtureData function"
)
except
Exception
as
e
:
logger
.
error
(
f
"Failed to call JavaScript updateFixtureData: {e}"
)
class
NativeOverlayWidget
(
QWidget
):
class
NativeOverlayWidget
(
QWidget
):
"""Native Qt overlay widget - no WebEngine to prevent freezing"""
"""Native Qt overlay widget - no WebEngine to prevent freezing"""
...
@@ -1271,6 +1359,11 @@ class PlayerWindow(QMainWindow):
...
@@ -1271,6 +1359,11 @@ class PlayerWindow(QMainWindow):
self
.
overlay_timer
.
timeout
.
connect
(
self
.
update_overlay_periodically
)
self
.
overlay_timer
.
timeout
.
connect
(
self
.
update_overlay_periodically
)
self
.
overlay_timer
.
start
(
1000
)
# Update every second
self
.
overlay_timer
.
start
(
1000
)
# Update every second
# Fixtures data refresh timer
self
.
fixtures_timer
=
QTimer
()
self
.
fixtures_timer
.
timeout
.
connect
(
self
.
_refresh_fixtures_data
)
self
.
fixtures_timer
.
start
(
30000
)
# Refresh fixtures every 30 seconds
# Template rotation timer (initially disabled)
# Template rotation timer (initially disabled)
self
.
template_rotation_timer
=
QTimer
()
self
.
template_rotation_timer
=
QTimer
()
self
.
template_rotation_timer
.
timeout
.
connect
(
self
.
_rotate_template
)
self
.
template_rotation_timer
.
timeout
.
connect
(
self
.
_rotate_template
)
...
@@ -1744,9 +1837,89 @@ class PlayerWindow(QMainWindow):
...
@@ -1744,9 +1837,89 @@ class PlayerWindow(QMainWindow):
}
}
if
time_data
and
current_time
:
# Ensure we have valid data
if
time_data
and
current_time
:
# Ensure we have valid data
self
.
_update_overlay_safe
(
overlay_view
,
time_data
)
self
.
_update_overlay_safe
(
overlay_view
,
time_data
)
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"Periodic overlay update failed: {e}"
)
logger
.
error
(
f
"Periodic overlay update failed: {e}"
)
def
_refresh_fixtures_data
(
self
):
"""Refresh fixtures data and send to overlay (called by timer)"""
try
:
logger
.
debug
(
"Refreshing fixtures data..."
)
self
.
_send_fixtures_to_overlay
()
except
Exception
as
e
:
logger
.
error
(
f
"Failed to refresh fixtures data: {e}"
)
def
_send_fixtures_to_overlay
(
self
):
"""Send fixtures data to the overlay via WebChannel"""
try
:
# Fetch fixtures data
fixtures_data
=
self
.
_fetch_fixtures_data
()
# Send data to overlay
if
hasattr
(
self
,
'window_overlay'
)
and
self
.
window_overlay
:
if
fixtures_data
:
logger
.
info
(
f
"Sending fixtures data to overlay: {len(fixtures_data.get('matches', []))} matches"
)
# Send via WebChannel signal - primary method
if
hasattr
(
self
.
window_overlay
,
'overlay_channel'
)
and
self
.
window_overlay
.
overlay_channel
:
self
.
window_overlay
.
overlay_channel
.
send_fixture_data_update
(
fixtures_data
)
logger
.
debug
(
"Sent fixtures data via WebChannel signal"
)
# Also try calling JavaScript functions directly as fallback
try
:
if
hasattr
(
self
.
window_overlay
,
'page'
):
page
=
self
.
window_overlay
.
page
()
if
page
:
# Try updateFixtureData function
page
.
runJavaScript
(
f
"updateFixtureData({json.dumps(fixtures_data)});"
)
# Also try updateFixtures function for compatibility
page
.
runJavaScript
(
f
"updateFixtures({json.dumps(fixtures_data)});"
)
logger
.
debug
(
"Sent fixtures data via JavaScript function calls"
)
except
Exception
as
js_error
:
logger
.
debug
(
f
"JavaScript call failed: {js_error}"
)
else
:
logger
.
warning
(
"No fixtures data available to send to overlay"
)
# Send empty data to trigger fallback
empty_data
=
{
'matches'
:
[]}
if
hasattr
(
self
.
window_overlay
,
'overlay_channel'
)
and
self
.
window_overlay
.
overlay_channel
:
self
.
window_overlay
.
overlay_channel
.
send_fixture_data_update
(
empty_data
)
else
:
logger
.
warning
(
"No overlay available to send fixtures data"
)
except
Exception
as
e
:
logger
.
error
(
f
"Failed to send fixtures data to overlay: {e}"
)
def
_fetch_fixtures_data
(
self
):
"""Fetch fixtures data from the web API"""
try
:
import
requests
from
datetime
import
datetime
,
date
base_url
=
self
.
_get_web_server_base_url
()
api_url
=
f
"{base_url}/api/cashier/pending-matches"
logger
.
info
(
f
"Fetching fixtures data from: {api_url}"
)
# Make API request
response
=
requests
.
get
(
api_url
,
timeout
=
10
)
if
response
.
status_code
==
200
:
data
=
response
.
json
()
if
data
.
get
(
'success'
)
and
data
.
get
(
'matches'
):
matches
=
data
[
'matches'
]
logger
.
info
(
f
"Successfully fetched {len(matches)} matches from API"
)
return
{
'matches'
:
matches
}
else
:
logger
.
warning
(
f
"API returned success=false or no matches: {data}"
)
return
None
else
:
logger
.
error
(
f
"API request failed with status {response.status_code}: {response.text}"
)
return
None
except
Exception
as
e
:
logger
.
error
(
f
"Failed to fetch fixtures data: {e}"
)
return
None
def
mouseMoveEvent
(
self
,
event
):
def
mouseMoveEvent
(
self
,
event
):
"""Show controls on mouse movement"""
"""Show controls on mouse movement"""
...
@@ -2019,6 +2192,10 @@ class QtVideoPlayer(QObject):
...
@@ -2019,6 +2192,10 @@ class QtVideoPlayer(QObject):
self
.
window
:
Optional
[
PlayerWindow
]
=
None
self
.
window
:
Optional
[
PlayerWindow
]
=
None
self
.
mutex
=
QMutex
()
self
.
mutex
=
QMutex
()
# Progress update throttling (2 per second = 500ms minimum interval)
self
.
last_progress_update_time
=
0.0
self
.
progress_update_interval
=
0.5
# 500ms
# Set web dashboard URL for API calls
# Set web dashboard URL for API calls
self
.
web_dashboard_url
=
"http://localhost:5000"
# Default web dashboard URL
self
.
web_dashboard_url
=
"http://localhost:5000"
# Default web dashboard URL
...
@@ -2038,22 +2215,103 @@ class QtVideoPlayer(QObject):
...
@@ -2038,22 +2215,103 @@ class QtVideoPlayer(QObject):
# Default web server configuration - matches main.py defaults
# Default web server configuration - matches main.py defaults
host
=
"127.0.0.1"
# Default host
host
=
"127.0.0.1"
# Default host
port
=
5001
# Default port
port
=
5001
# Default port
# Try to get web server settings if available
# Try to get web server settings if available
if
hasattr
(
self
,
'_message_bus'
)
and
self
.
_message_bus
:
if
hasattr
(
self
,
'_message_bus'
)
and
self
.
_message_bus
:
# Check if we can get web server info from message bus or settings
# Check if we can get web server info from message bus or settings
# For now, use defaults since we don't have direct access to web settings
# For now, use defaults since we don't have direct access to web settings
pass
pass
# Construct base URL
# Construct base URL
base_url
=
f
"http://{host}:{port}"
base_url
=
f
"http://{host}:{port}"
logger
.
debug
(
f
"Web server base URL determined as: {base_url}"
)
logger
.
debug
(
f
"Web server base URL determined as: {base_url}"
)
return
base_url
return
base_url
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"Failed to determine web server base URL: {e}"
)
logger
.
error
(
f
"Failed to determine web server base URL: {e}"
)
# Return default fallback
# Return default fallback
return
"http://127.0.0.1:5001"
return
"http://127.0.0.1:5001"
def
_fetch_fixtures_data
(
self
)
->
Optional
[
Dict
[
str
,
Any
]]:
"""Fetch fixtures data from the web API"""
try
:
import
requests
from
datetime
import
datetime
,
date
base_url
=
self
.
_get_web_server_base_url
()
api_url
=
f
"{base_url}/api/cashier/pending-matches"
logger
.
info
(
f
"Fetching fixtures data from: {api_url}"
)
# Make API request
response
=
requests
.
get
(
api_url
,
timeout
=
10
)
if
response
.
status_code
==
200
:
data
=
response
.
json
()
if
data
.
get
(
'success'
)
and
data
.
get
(
'matches'
):
matches
=
data
[
'matches'
]
logger
.
info
(
f
"Successfully fetched {len(matches)} matches from API"
)
return
{
'matches'
:
matches
}
else
:
logger
.
warning
(
f
"API returned success=false or no matches: {data}"
)
return
None
else
:
logger
.
error
(
f
"API request failed with status {response.status_code}: {response.text}"
)
return
None
except
Exception
as
e
:
logger
.
error
(
f
"Failed to fetch fixtures data: {e}"
)
return
None
def
_refresh_fixtures_data
(
self
):
"""Refresh fixtures data and send to overlay (called by timer)"""
try
:
logger
.
debug
(
"Refreshing fixtures data..."
)
self
.
_send_fixtures_to_overlay
()
except
Exception
as
e
:
logger
.
error
(
f
"Failed to refresh fixtures data: {e}"
)
def
_send_fixtures_to_overlay
(
self
,
fixtures_data
:
Optional
[
Dict
[
str
,
Any
]]
=
None
):
"""Send fixtures data to the overlay via WebChannel"""
try
:
# If no data provided, fetch it
if
fixtures_data
is
None
:
fixtures_data
=
self
.
_fetch_fixtures_data
()
# Send data to overlay
if
hasattr
(
self
,
'window_overlay'
)
and
self
.
window_overlay
:
if
fixtures_data
:
logger
.
info
(
f
"Sending fixtures data to overlay: {len(fixtures_data.get('matches', []))} matches"
)
# Send via WebChannel signal - primary method
if
hasattr
(
self
.
window_overlay
,
'overlay_channel'
)
and
self
.
window_overlay
.
overlay_channel
:
self
.
window_overlay
.
overlay_channel
.
send_fixture_data_update
(
fixtures_data
)
logger
.
debug
(
"Sent fixtures data via WebChannel signal"
)
# Also try calling JavaScript functions directly as fallback
try
:
if
hasattr
(
self
.
window_overlay
,
'page'
):
page
=
self
.
window_overlay
.
page
()
if
page
:
# Try updateFixtureData function
page
.
runJavaScript
(
f
"updateFixtureData({json.dumps(fixtures_data)});"
)
# Also try updateFixtures function for compatibility
page
.
runJavaScript
(
f
"updateFixtures({json.dumps(fixtures_data)});"
)
logger
.
debug
(
"Sent fixtures data via JavaScript function calls"
)
except
Exception
as
js_error
:
logger
.
debug
(
f
"JavaScript call failed: {js_error}"
)
else
:
logger
.
warning
(
"No fixtures data available to send to overlay"
)
# Send empty data to trigger fallback
empty_data
=
{
'matches'
:
[]}
if
hasattr
(
self
.
window_overlay
,
'overlay_channel'
)
and
self
.
window_overlay
.
overlay_channel
:
self
.
window_overlay
.
overlay_channel
.
send_fixture_data_update
(
empty_data
)
else
:
logger
.
warning
(
"No overlay available to send fixtures data"
)
except
Exception
as
e
:
logger
.
error
(
f
"Failed to send fixtures data to overlay: {e}"
)
def
initialize
(
self
)
->
bool
:
def
initialize
(
self
)
->
bool
:
"""Initialize PyQt6 application and components"""
"""Initialize PyQt6 application and components"""
...
@@ -2253,6 +2511,12 @@ class QtVideoPlayer(QObject):
...
@@ -2253,6 +2511,12 @@ class QtVideoPlayer(QObject):
'showStats'
:
False
,
'showStats'
:
False
,
'webServerBaseUrl'
:
self
.
_get_web_server_base_url
()
'webServerBaseUrl'
:
self
.
_get_web_server_base_url
()
}
}
# Fetch and include fixture data if available
fixture_data
=
self
.
_fetch_fixture_data
()
if
fixture_data
:
default_data
[
'fixtures'
]
=
fixture_data
.
get
(
'matches'
,
[])
logger
.
info
(
f
"Included {len(default_data['fixtures'])} fixtures in default overlay"
)
if
not
self
.
window
:
if
not
self
.
window
:
logger
.
debug
(
"Window not ready for overlay loading"
)
logger
.
debug
(
"Window not ready for overlay loading"
)
...
@@ -2630,21 +2894,25 @@ class QtVideoPlayer(QObject):
...
@@ -2630,21 +2894,25 @@ class QtVideoPlayer(QObject):
logger
.
error
(
f
"Failed to handle video loaded event: {e}"
)
logger
.
error
(
f
"Failed to handle video loaded event: {e}"
)
def
_send_progress_update
(
self
):
def
_send_progress_update
(
self
):
"""Send video progress update"""
"""Send video progress update (throttled to 2 per second)"""
try
:
try
:
if
self
.
window
and
self
.
window
.
media_player
.
duration
()
>
0
:
# Throttle progress updates to 2 per second (500ms minimum interval)
position
=
self
.
window
.
media_player
.
position
()
current_time
=
time
.
time
()
duration
=
self
.
window
.
media_player
.
duration
()
if
current_time
-
self
.
last_progress_update_time
>=
self
.
progress_update_interval
:
percentage
=
(
position
/
duration
)
*
100
if
duration
>
0
else
0
if
self
.
window
and
self
.
window
.
media_player
.
duration
()
>
0
:
position
=
self
.
window
.
media_player
.
position
()
progress_message
=
MessageBuilder
.
video_progress
(
duration
=
self
.
window
.
media_player
.
duration
()
sender
=
self
.
name
,
percentage
=
(
position
/
duration
)
*
100
if
duration
>
0
else
0
position
=
position
/
1000.0
,
# Convert to seconds
duration
=
duration
/
1000.0
,
# Convert to seconds
progress_message
=
MessageBuilder
.
video_progress
(
percentage
=
percentage
sender
=
self
.
name
,
)
position
=
position
/
1000.0
,
# Convert to seconds
self
.
message_bus
.
publish
(
progress_message
,
broadcast
=
True
)
duration
=
duration
/
1000.0
,
# Convert to seconds
percentage
=
percentage
)
self
.
message_bus
.
publish
(
progress_message
,
broadcast
=
True
)
self
.
last_progress_update_time
=
current_time
except
Exception
as
e
:
except
Exception
as
e
:
logger
.
error
(
f
"Failed to send progress update: {e}"
)
logger
.
error
(
f
"Failed to send progress update: {e}"
)
...
@@ -2764,16 +3032,16 @@ class QtVideoPlayer(QObject):
...
@@ -2764,16 +3032,16 @@ class QtVideoPlayer(QObject):
template_data
=
message
.
data
.
get
(
"template_data"
,
{})
template_data
=
message
.
data
.
get
(
"template_data"
,
{})
reload_template
=
template_data
.
get
(
"reload_template"
,
False
)
reload_template
=
template_data
.
get
(
"reload_template"
,
False
)
load_specific_template
=
template_data
.
get
(
"load_specific_template"
,
""
)
load_specific_template
=
template_data
.
get
(
"load_specific_template"
,
""
)
if
self
.
debug_overlay
:
if
self
.
debug_overlay
:
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Template change message received"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Template change message received"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Template name: {template_name}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Template name: {template_name}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Reload template: {reload_template}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Reload template: {reload_template}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Load specific template: {load_specific_template}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Load specific template: {load_specific_template}"
)
if
self
.
window
and
hasattr
(
self
.
window
,
'window_overlay'
):
if
self
.
window
and
hasattr
(
self
.
window
,
'window_overlay'
):
overlay_view
=
self
.
window
.
window_overlay
overlay_view
=
self
.
window
.
window_overlay
# Check video player state before template change
# Check video player state before template change
if
hasattr
(
self
.
window
,
'media_player'
)
and
self
.
debug_overlay
:
if
hasattr
(
self
.
window
,
'media_player'
)
and
self
.
debug_overlay
:
video_state
=
self
.
window
.
media_player
.
playbackState
()
video_state
=
self
.
window
.
media_player
.
playbackState
()
...
@@ -2785,7 +3053,7 @@ class QtVideoPlayer(QObject):
...
@@ -2785,7 +3053,7 @@ class QtVideoPlayer(QObject):
if
hasattr
(
self
.
window
,
'overlay_window'
)
and
self
.
debug_overlay
:
if
hasattr
(
self
.
window
,
'overlay_window'
)
and
self
.
debug_overlay
:
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Overlay window geometry: {self.window.overlay_window.geometry()}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Overlay window geometry: {self.window.overlay_window.geometry()}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Overlay window visible: {self.window.overlay_window.isVisible()}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Overlay window visible: {self.window.overlay_window.isVisible()}"
)
# CRITICAL FIX: Protect video context during template changes
# CRITICAL FIX: Protect video context during template changes
video_widget
=
None
video_widget
=
None
if
hasattr
(
self
.
window
,
'video_widget'
)
and
hasattr
(
self
.
window
.
video_widget
,
'get_video_widget'
):
if
hasattr
(
self
.
window
,
'video_widget'
)
and
hasattr
(
self
.
window
.
video_widget
,
'get_video_widget'
):
...
@@ -2799,6 +3067,19 @@ class QtVideoPlayer(QObject):
...
@@ -2799,6 +3067,19 @@ class QtVideoPlayer(QObject):
logger
.
debug
(
f
"GREEN SCREEN DEBUG: About to load specific template: {load_specific_template}"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: About to load specific template: {load_specific_template}"
)
logger
.
debug
(
f
"GREEN SCREEN FIX: Protecting video rendering during template load"
)
logger
.
debug
(
f
"GREEN SCREEN FIX: Protecting video rendering during template load"
)
overlay_view
.
load_template
(
load_specific_template
)
overlay_view
.
load_template
(
load_specific_template
)
# If loading fixtures template, fetch and send fixture data
if
load_specific_template
==
"fixtures.html"
:
logger
.
info
(
"Loading fixtures template, fetching fixture data..."
)
fixture_data
=
self
.
_fetch_fixture_data
()
if
fixture_data
:
# Send fixture data to the overlay
fixture_payload
=
{
'fixtures'
:
fixture_data
.
get
(
'matches'
,
[])}
self
.
window
.
update_fixture_data
(
fixture_payload
)
logger
.
info
(
f
"Sent {len(fixture_payload['fixtures'])} fixtures to fixtures overlay"
)
else
:
logger
.
warning
(
"No fixture data available for fixtures template"
)
if
self
.
debug_overlay
:
if
self
.
debug_overlay
:
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Specific template load initiated"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Specific template load initiated"
)
# Otherwise reload current template if requested and using WebEngine overlay
# Otherwise reload current template if requested and using WebEngine overlay
...
@@ -2809,7 +3090,7 @@ class QtVideoPlayer(QObject):
...
@@ -2809,7 +3090,7 @@ class QtVideoPlayer(QObject):
overlay_view
.
reload_current_template
()
overlay_view
.
reload_current_template
()
if
self
.
debug_overlay
:
if
self
.
debug_overlay
:
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Current template reload initiated"
)
logger
.
debug
(
f
"GREEN SCREEN DEBUG: Current template reload initiated"
)
# CRITICAL FIX: Force video widget refresh after template change
# CRITICAL FIX: Force video widget refresh after template change
if
video_widget
and
self
.
debug_overlay
:
if
video_widget
and
self
.
debug_overlay
:
logger
.
debug
(
f
"GREEN SCREEN FIX: Forcing video widget refresh after template change"
)
logger
.
debug
(
f
"GREEN SCREEN FIX: Forcing video widget refresh after template change"
)
...
...
mbetterclient/qt_player/templates/fixtures.html
View file @
5b0da3e1
...
@@ -76,11 +76,11 @@
...
@@ -76,11 +76,11 @@
}
}
.fixtures-table
th
{
.fixtures-table
th
{
padding
:
15px
10
px
;
padding
:
8px
4
px
;
text-align
:
center
;
text-align
:
center
;
background
:
rgba
(
255
,
255
,
255
,
0.1
);
background
:
rgba
(
255
,
255
,
255
,
0.1
);
font-weight
:
bold
;
font-weight
:
bold
;
font-size
:
1
4
px
;
font-size
:
1
1
px
;
text-transform
:
uppercase
;
text-transform
:
uppercase
;
letter-spacing
:
1px
;
letter-spacing
:
1px
;
border-radius
:
8px
;
border-radius
:
8px
;
...
@@ -89,7 +89,7 @@
...
@@ -89,7 +89,7 @@
}
}
.fixtures-table
td
{
.fixtures-table
td
{
padding
:
12px
10
px
;
padding
:
8px
6
px
;
text-align
:
center
;
text-align
:
center
;
background
:
rgba
(
255
,
255
,
255
,
0.05
);
background
:
rgba
(
255
,
255
,
255
,
0.05
);
border-radius
:
6px
;
border-radius
:
6px
;
...
@@ -100,6 +100,45 @@
...
@@ -100,6 +100,45 @@
.fixtures-table
tbody
tr
:hover
td
{
.fixtures-table
tbody
tr
:hover
td
{
background
:
rgba
(
255
,
255
,
255
,
0.15
);
background
:
rgba
(
255
,
255
,
255
,
0.15
);
}
}
.next-match-info
{
text-align
:
center
;
color
:
rgba
(
255
,
255
,
255
,
0.9
);
font-size
:
16px
;
margin-bottom
:
10px
;
font-weight
:
bold
;
text-shadow
:
1px
1px
2px
rgba
(
0
,
0
,
0
,
0.5
);
}
.countdown-timer
{
text-align
:
center
;
color
:
#ffeb3b
;
font-size
:
24px
;
font-weight
:
bold
;
margin-bottom
:
15px
;
text-shadow
:
2px
2px
4px
rgba
(
0
,
0
,
0
,
0.8
);
background
:
rgba
(
0
,
0
,
0
,
0.3
);
padding
:
8px
16px
;
border-radius
:
10px
;
border
:
2px
solid
rgba
(
255
,
235
,
59
,
0.3
);
}
.countdown-timer.warning
{
color
:
#ff9800
;
border-color
:
rgba
(
255
,
152
,
0
,
0.5
);
}
.countdown-timer.urgent
{
color
:
#f44336
;
border-color
:
rgba
(
244
,
67
,
54
,
0.5
);
animation
:
pulse
1s
infinite
;
}
@keyframes
pulse
{
0
%
{
transform
:
scale
(
1
);
}
50
%
{
transform
:
scale
(
1.05
);
}
100
%
{
transform
:
scale
(
1
);
}
}
.match-info
{
.match-info
{
font-weight
:
bold
;
font-weight
:
bold
;
...
@@ -244,6 +283,8 @@
...
@@ -244,6 +283,8 @@
<div
class=
"overlay-container"
>
<div
class=
"overlay-container"
>
<div
class=
"fixtures-panel"
id=
"fixturesPanel"
>
<div
class=
"fixtures-panel"
id=
"fixturesPanel"
>
<div
class=
"fixtures-title"
>
Today's matches
</div>
<div
class=
"fixtures-title"
>
Today's matches
</div>
<div
class=
"next-match-info"
id=
"nextMatchInfo"
style=
"display: none;"
></div>
<div
class=
"countdown-timer"
id=
"countdownTimer"
style=
"display: none;"
></div>
<div
class=
"loading-message"
id=
"loadingMessage"
style=
"display: none;"
>
Loading fixture data...
</div>
<div
class=
"loading-message"
id=
"loadingMessage"
style=
"display: none;"
>
Loading fixture data...
</div>
<div
id=
"fixturesContent"
style=
"display: none;"
>
<div
id=
"fixturesContent"
style=
"display: none;"
>
<table
class=
"fixtures-table"
id=
"fixturesTable"
>
<table
class=
"fixtures-table"
id=
"fixturesTable"
>
...
@@ -275,108 +316,109 @@
...
@@ -275,108 +316,109 @@
let
overlayData
=
{};
let
overlayData
=
{};
let
fixturesData
=
null
;
let
fixturesData
=
null
;
let
outcomesData
=
null
;
let
outcomesData
=
null
;
let
countdownInterval
=
null
;
let
nextMatchStartTime
=
null
;
// Web server configuration - will be set via WebChannel
// Web server configuration - will be set via WebChannel
let
webServerBaseUrl
=
'http://127.0.0.1:5001'
;
// Default fallback
let
webServerBaseUrl
=
'http://127.0.0.1:5001'
;
// Default fallback
// Debug logging function that sends messages to Qt application logs
function
debugLog
(
message
,
level
=
'info'
)
{
try
{
// Try to send to Qt WebChannel if available
if
(
typeof
qt
!==
'undefined'
&&
qt
.
webChannelTransport
)
{
// Send debug message to Qt application
if
(
window
.
sendDebugMessage
)
{
window
.
sendDebugMessage
(
`[FIXTURES]
${
message
}
`
);
}
}
}
catch
(
e
)
{
// Fallback to console if WebChannel not available - use original console to avoid recursion
originalConsoleLog
(
`[FIXTURES FALLBACK]
${
message
}
`
);
}
// Always log to console as well for browser debugging - use original to avoid recursion
originalConsoleLog
(
`🔍 DEBUG:
${
message
}
`
);
}
// Store original console.log before overriding
const
originalConsoleLog
=
console
.
log
;
// Override console.log to redirect all console.log calls to Qt application logs
console
.
log
=
function
(...
args
)
{
// Convert arguments to string message
const
message
=
args
.
map
(
arg
=>
typeof
arg
===
'object'
?
JSON
.
stringify
(
arg
)
:
String
(
arg
)
).
join
(
' '
);
// Send to Qt application logs directly (avoid calling debugLog to prevent recursion)
try
{
if
(
typeof
qt
!==
'undefined'
&&
qt
.
webChannelTransport
)
{
if
(
window
.
sendDebugMessage
)
{
window
.
sendDebugMessage
(
`[FIXTURES]
${
message
}
`
);
}
}
}
catch
(
e
)
{
// Fallback handled below
}
// Always call original console.log for browser debugging
originalConsoleLog
.
apply
(
console
,
args
);
};
// Function to receive fixture data from Qt WebChannel
function
updateFixtureData
(
data
)
{
console
.
log
(
'🔍 DEBUG: Received fixture data from WebChannel:'
,
data
);
if
(
data
&&
data
.
fixtures
)
{
fixturesData
=
data
.
fixtures
;
renderFixtures
();
}
else
if
(
data
&&
data
.
matches
)
{
fixturesData
=
data
.
matches
;
renderFixtures
();
}
else
{
console
.
log
(
'🔍 DEBUG: No valid fixture data in WebChannel update, showing fallback'
);
showFallbackMatches
();
}
}
// Function to update overlay data (called by Qt WebChannel)
// Function to update overlay data (called by Qt WebChannel)
function
updateOverlayData
(
data
)
{
function
updateOverlayData
(
data
)
{
console
.
log
(
'Received overlay data:'
,
data
);
console
.
log
(
'Received overlay data:'
,
data
);
overlayData
=
data
||
{};
overlayData
=
data
||
{};
// Update web server base URL if provided
// Update web server base URL if provided
if
(
data
&&
data
.
webServerBaseUrl
)
{
if
(
data
&&
data
.
webServerBaseUrl
)
{
webServerBaseUrl
=
data
.
webServerBaseUrl
;
webServerBaseUrl
=
data
.
webServerBaseUrl
;
console
.
log
(
'Updated web server base URL:'
,
webServerBaseUrl
);
console
.
log
(
'Updated web server base URL:'
,
webServerBaseUrl
);
}
}
// Check if we have fixtures data
// Check if we have fixtures data
from WebChannel
if
(
data
&&
data
.
fixtures
)
{
if
(
data
&&
data
.
fixtures
)
{
console
.
log
(
'🔍 DEBUG: Received fixtures data from WebChannel'
);
fixturesData
=
data
.
fixtures
;
fixturesData
=
data
.
fixtures
;
renderFixtures
();
renderFixtures
();
}
else
if
(
data
&&
data
.
matches
)
{
console
.
log
(
'🔍 DEBUG: Received matches data from WebChannel'
);
fixturesData
=
data
.
matches
;
renderFixtures
();
}
else
{
}
else
{
// Fetch fixtures data from API
console
.
log
(
'🔍 DEBUG: No fixtures data in WebChannel update, will wait for updateFixtureData call'
);
fetchFixturesData
();
// Don't fetch from API - wait for Python side to provide data via updateFixtureData
}
}
}
}
// Fetch fixtures data from the API
async
function
fetchFixturesData
()
{
// Function to receive fixture data from Qt WebChannel (called by Python) - new method
try
{
function
updateFixtures
(
data
)
{
console
.
log
(
'Fetching fixtures data from API...'
);
console
.
log
(
'🔍 DEBUG: Received fixtures data from WebChannel via updateFixtures:'
,
data
);
updateFixtureData
(
data
);
// Try multiple API endpoints with different authentication levels
const
apiEndpoints
=
[
`
${
webServerBaseUrl
}
/api/cashier/pending-matches`
,
`
${
webServerBaseUrl
}
/api/fixtures`
,
`
${
webServerBaseUrl
}
/api/status`
// Fallback to basic status endpoint
];
let
apiData
=
null
;
let
usedEndpoint
=
null
;
for
(
const
endpoint
of
apiEndpoints
)
{
try
{
console
.
log
(
`Trying API endpoint:
${
endpoint
}
`
);
const
response
=
await
fetch
(
endpoint
,
{
method
:
'GET'
,
headers
:
{
'Content-Type'
:
'application/json'
},
credentials
:
'include'
// Include cookies for authentication
});
if
(
response
.
ok
)
{
const
data
=
await
response
.
json
();
console
.
log
(
`API Response from
${
endpoint
}
:`
,
data
);
if
(
data
.
success
)
{
apiData
=
data
;
usedEndpoint
=
endpoint
;
break
;
}
}
else
{
console
.
warn
(
`API endpoint
${
endpoint
}
returned status
${
response
.
status
}
`
);
}
}
catch
(
endpointError
)
{
console
.
warn
(
`Failed to fetch from
${
endpoint
}
:`
,
endpointError
);
continue
;
}
}
if
(
apiData
&&
apiData
.
matches
&&
apiData
.
matches
.
length
>
0
)
{
console
.
log
(
`Found
${
apiData
.
matches
.
length
}
matches from
${
usedEndpoint
}
`
);
fixturesData
=
apiData
.
matches
;
renderFixtures
();
return
Promise
.
resolve
();
}
else
if
(
apiData
&&
apiData
.
fixtures
&&
apiData
.
fixtures
.
length
>
0
)
{
// Handle fixtures endpoint format
console
.
log
(
`Found
${
apiData
.
fixtures
.
length
}
fixtures from
${
usedEndpoint
}
`
);
// Convert fixtures to matches format
fixturesData
=
[];
apiData
.
fixtures
.
forEach
(
fixture
=>
{
if
(
fixture
.
matches
)
{
fixturesData
.
push
(...
fixture
.
matches
);
}
});
if
(
fixturesData
.
length
>
0
)
{
renderFixtures
();
return
Promise
.
resolve
();
}
}
// If we reach here, no valid data was found
console
.
log
(
'No fixture data available from any API endpoint, will show fallback'
);
return
Promise
.
reject
(
'No API data available'
);
}
catch
(
error
)
{
console
.
error
(
'Error fetching fixtures data:'
,
error
);
return
Promise
.
reject
(
error
);
}
}
}
// Show fallback sample matches when API is not available
// Show fallback sample matches when API is not available
function
showFallbackMatches
()
{
function
showFallbackMatches
()
{
console
.
log
(
'Showing fallback sample matches'
);
console
.
log
(
'🔍 DEBUG: Showing fallback sample matches - API FAILED'
);
console
.
log
(
'🔍 DEBUG: This indicates the API endpoints are not working properly'
);
fixturesData
=
[
fixturesData
=
[
{
{
id
:
1
,
id
:
1
,
...
@@ -407,6 +449,7 @@
...
@@ -407,6 +449,7 @@
]
]
}
}
];
];
console
.
log
(
'🔍 DEBUG: Fallback data loaded, rendering fixtures'
);
renderFixtures
();
renderFixtures
();
}
}
...
@@ -583,54 +626,102 @@
...
@@ -583,54 +626,102 @@
// Initialize when DOM is loaded
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
document.addEventListener('DOMContentLoaded', function() {
console.log('Fixtures overlay initialized - attempting to fetch real data');
console.log('🔍 DEBUG: Fixtures overlay initialized - waiting for WebChannel data');
console.log('🔍 DEBUG: DOM ready, WebChannel will provide fixture data');
// Show loading message initially
// Show loading message initially
document.getElementById('fixturesContent').style.display = 'none';
document.getElementById('fixturesContent').style.display = 'none';
document.getElementById('noMatches').style.display = 'none';
document.getElementById('noMatches').style.display = 'none';
document.getElementById('loadingMessage').style.display = 'block';
document.getElementById('loadingMessage').style.display = 'block';
document.getElementById('loadingMessage').textContent = 'Loading live fixture data...';
document.getElementById('loadingMessage').textContent = 'Loading live fixture data...';
// Start fetching real data immediately
// Wait for WebChannel to provide data - no direct API fetching
fetchFixturesData().then(() => {
console.log('🔍 DEBUG: Waiting for Python side to provide fixture data via WebChannel');
// If API fails completely, show fallback data after a short delay
setTimeout(() => {
// Fallback: Try to trigger data load via WebChannel after 1 second
if (!fixturesData || fixturesData.length === 0) {
setTimeout(function() {
console.log('No data loaded after API attempts, forcing fallback display');
console.log('🔍 DEBUG: Fallback - trying to trigger data load via WebChannel');
showFallbackMatches();
if (typeof qt !== 'undefined' && qt.webChannelTransport) {
try {
new QWebChannel(qt.webChannelTransport, function(channel) {
if (channel.objects.overlay && channel.objects.overlay.trigger_fixtures_data_load) {
console.log('🔍 DEBUG: Calling trigger_fixtures_data_load from fallback timer');
channel.objects.overlay.trigger_fixtures_data_load();
}
});
} catch (e) {
console.log('🔍 DEBUG: Fallback WebChannel trigger failed:', e);
}
}
}, 2000);
}
}).catch(() => {
}, 1000);
console.log('API fetch failed, showing fallback data');
showFallbackMatches();
// Fallback timeout - if no data received after 10 seconds, show fallback
});
setTimeout(() => {
if (!fixturesData || fixturesData.length === 0) {
// Refresh data every 30 seconds
console.log('🔍 DEBUG: No data received from WebChannel after timeout, showing fallback');
setInterval(function() {
showFallbackMatches();
console.log('Refreshing fixture data...');
} else {
fetchFixturesData();
console.log('🔍 DEBUG: Data received from WebChannel, no fallback needed');
}, 30000);
}
}, 10000);
});
});
// Qt WebChannel initialization (when available)
// Qt WebChannel initialization (when available)
if (typeof QWebChannel !== 'undefined') {
if (typeof QWebChannel !== 'undefined') {
console.log('🔍 DEBUG: QWebChannel available, initializing...');
new QWebChannel(qt.webChannelTransport, function(channel) {
new QWebChannel(qt.webChannelTransport, function(channel) {
console.log('WebChannel initialized for fixtures overlay');
console.log('🔍 DEBUG: WebChannel initialized for fixtures overlay');
console.log('🔍 DEBUG: Available channel objects:', Object.keys(channel.objects));
// Connect to overlay object if available
// Connect to overlay object if available
if (channel.objects.overlay) {
if (channel.objects.overlay) {
console.log('🔍 DEBUG: Overlay object found in WebChannel');
console.log('🔍 DEBUG: Overlay object methods:', Object.getOwnPropertyNames(channel.objects.overlay));
channel.objects.overlay.dataChanged.connect(function(data) {
channel.objects.overlay.dataChanged.connect(function(data) {
console.log('🔍 DEBUG: Overlay dataChanged signal received:', data);
updateOverlayData(data);
updateOverlayData(data);
});
});
// Connect fixture data signal
if (channel.objects.overlay.fixtureDataUpdated) {
console.log('🔍 DEBUG: Connecting to fixtureDataUpdated signal');
channel.objects.overlay.fixtureDataUpdated.connect(function(data) {
console.log('🔍 DEBUG: Fixture data signal received:', data);
updateFixtureData(data);
});
} else {
console.log('🔍 DEBUG: fixtureDataUpdated signal not available on overlay object');
}
// Get initial data
// Get initial data
if (channel.objects.overlay.getCurrentData) {
if (channel.objects.overlay.getCurrentData) {
console.log('🔍 DEBUG: Calling getCurrentData for initial data');
channel.objects.overlay.getCurrentData(function(data) {
channel.objects.overlay.getCurrentData(function(data) {
console.log('🔍 DEBUG: Received initial data from getCurrentData:', data);
updateOverlayData(data);
updateOverlayData(data);
});
});
} else {
console.log('🔍 DEBUG: getCurrentData method not available');
}
// Try to manually trigger fixtures data load
console.log('🔍 DEBUG: Attempting to manually trigger fixtures data load');
if (channel.objects.overlay.trigger_fixtures_data_load) {
console.log('🔍 DEBUG: Calling trigger_fixtures_data_load manually');
channel.objects.overlay.trigger_fixtures_data_load();
} else if (channel.objects.overlay.sendFixtureDataUpdate) {
console.log('🔍 DEBUG: Calling sendFixtureDataUpdate manually');
channel.objects.overlay.sendFixtureDataUpdate({'test': 'manual_trigger'});
} else {
console.log('🔍 DEBUG: No manual trigger method available');
}
}
} else {
console.log('🔍 DEBUG: No overlay object found in WebChannel');
}
}
});
});
} else {
console.log('🔍 DEBUG: QWebChannel not available, will rely on DOM ready event');
}
}
</script>
</script>
...
...
mbetterclient/web_dashboard/routes.py
View file @
5b0da3e1
...
@@ -1925,7 +1925,6 @@ def save_intro_templates():
...
@@ -1925,7 +1925,6 @@ def save_intro_templates():
@
api_bp
.
route
(
'/fixtures'
)
@
api_bp
.
route
(
'/fixtures'
)
@
api_bp
.
auth_manager
.
require_auth
if
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
else
login_required
def
get_fixtures
():
def
get_fixtures
():
"""Get all fixtures/matches grouped by fixture_id with calculated status"""
"""Get all fixtures/matches grouped by fixture_id with calculated status"""
try
:
try
:
...
@@ -2040,10 +2039,14 @@ def calculate_fixture_status(matches, today):
...
@@ -2040,10 +2039,14 @@ def calculate_fixture_status(matches, today):
@
api_bp
.
route
(
'/cashier/pending-matches'
)
@
api_bp
.
route
(
'/cashier/pending-matches'
)
@
api_bp
.
auth_manager
.
require_auth
if
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
else
login_required
def
get_cashier_pending_matches
():
def
get_cashier_pending_matches
():
"""Get pending matches from the correct fixture for cashier dashboard"""
"""Get pending matches from the correct fixture for cashier dashboard"""
try
:
try
:
# Allow access from localhost without authentication
if
request
.
remote_addr
==
'127.0.0.1'
:
pass
# Skip authentication
elif
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
:
api_bp
.
auth_manager
.
require_auth
()
from
..database.models
import
MatchModel
from
..database.models
import
MatchModel
from
datetime
import
datetime
,
date
,
timedelta
from
datetime
import
datetime
,
date
,
timedelta
...
@@ -2190,10 +2193,14 @@ def start_games():
...
@@ -2190,10 +2193,14 @@ def start_games():
@
api_bp
.
route
(
'/fixtures/<fixture_id>'
)
@
api_bp
.
route
(
'/fixtures/<fixture_id>'
)
@
api_bp
.
auth_manager
.
require_auth
if
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
else
login_required
def
get_fixture_details
(
fixture_id
):
def
get_fixture_details
(
fixture_id
):
"""Get all matches in a fixture by fixture_id"""
"""Get all matches in a fixture by fixture_id"""
try
:
try
:
# Allow access from localhost without authentication
if
request
.
remote_addr
==
'127.0.0.1'
:
pass
# Skip authentication
elif
hasattr
(
api_bp
,
'auth_manager'
)
and
api_bp
.
auth_manager
:
api_bp
.
auth_manager
.
require_auth
()
from
..database.models
import
MatchModel
,
MatchOutcomeModel
from
..database.models
import
MatchModel
,
MatchOutcomeModel
from
datetime
import
datetime
,
date
from
datetime
import
datetime
,
date
...
...
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