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
1f2b9534
Commit
1f2b9534
authored
Dec 17, 2025
by
Stefy Lanza (nextime / spora )
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
templates license and results bottom bar
parent
0a38c586
Changes
7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
581 additions
and
271 deletions
+581
-271
=4.0.0
=4.0.0
+0
-12
player.py
mbetterclient/qt_player/player.py
+107
-0
default.html
mbetterclient/qt_player/templates/default.html
+119
-38
fixtures.html
mbetterclient/qt_player/templates/fixtures.html
+73
-49
match.html
mbetterclient/qt_player/templates/match.html
+109
-35
text.html
mbetterclient/qt_player/templates/text.html
+173
-27
test_api.py
test_api.py
+0
-110
No files found.
=4.0.0
deleted
100644 → 0
View file @
0a38c586
Collecting flask-cors
Using cached flask_cors-6.0.1-py3-none-any.whl.metadata (5.3 kB)
Requirement already satisfied: flask>=0.9 in ./venv/lib/python3.13/site-packages (from flask-cors) (3.1.2)
Requirement already satisfied: Werkzeug>=0.7 in ./venv/lib/python3.13/site-packages (from flask-cors) (3.1.3)
Requirement already satisfied: blinker>=1.9.0 in ./venv/lib/python3.13/site-packages (from flask>=0.9->flask-cors) (1.9.0)
Requirement already satisfied: click>=8.1.3 in ./venv/lib/python3.13/site-packages (from flask>=0.9->flask-cors) (8.3.1)
Requirement already satisfied: itsdangerous>=2.2.0 in ./venv/lib/python3.13/site-packages (from flask>=0.9->flask-cors) (2.2.0)
Requirement already satisfied: jinja2>=3.1.2 in ./venv/lib/python3.13/site-packages (from flask>=0.9->flask-cors) (3.1.6)
Requirement already satisfied: markupsafe>=2.1.1 in ./venv/lib/python3.13/site-packages (from flask>=0.9->flask-cors) (3.0.3)
Using cached flask_cors-6.0.1-py3-none-any.whl (13 kB)
Installing collected packages: flask-cors
Successfully installed flask-cors-6.0.1
mbetterclient/qt_player/player.py
View file @
1f2b9534
...
@@ -280,6 +280,113 @@ class OverlayWebChannel(QObject):
...
@@ -280,6 +280,113 @@ class OverlayWebChannel(QObject):
logger
.
error
(
f
"QtWebChannel: Full traceback: {traceback.format_exc()}"
)
logger
.
error
(
f
"QtWebChannel: Full traceback: {traceback.format_exc()}"
)
return
json
.
dumps
([])
return
json
.
dumps
([])
@
pyqtSlot
(
result
=
str
)
def
getLicenseText
(
self
)
->
str
:
"""Provide license text to JavaScript via WebChannel"""
try
:
logger
.
info
(
"QtWebChannel: Getting license text from database"
)
if
not
self
.
db_manager
:
logger
.
error
(
"QtWebChannel: Database manager not available"
)
return
json
.
dumps
({
"license_text"
:
"License text not available - database not connected"
})
# Get license text from database
license_text
=
self
.
_get_license_text_from_database
()
logger
.
debug
(
f
"QtWebChannel: Retrieved license text from database"
)
return
json
.
dumps
({
"license_text"
:
license_text
})
except
Exception
as
e
:
logger
.
error
(
f
"QtWebChannel: Failed to get license text: {e}"
)
return
json
.
dumps
({
"license_text"
:
"License text not available - error occurred"
})
@
pyqtSlot
(
result
=
str
)
def
getCompletedMatches
(
self
)
->
str
:
"""Provide last 3 completed matches to JavaScript via WebChannel"""
try
:
logger
.
info
(
"QtWebChannel: Getting completed matches from database"
)
if
not
self
.
db_manager
:
logger
.
error
(
"QtWebChannel: Database manager not available"
)
return
json
.
dumps
([])
# Get completed matches from database
completed_matches
=
self
.
_get_completed_matches_from_database
()
logger
.
debug
(
f
"QtWebChannel: Retrieved {len(completed_matches)} completed matches from database"
)
return
json
.
dumps
(
completed_matches
)
except
Exception
as
e
:
logger
.
error
(
f
"QtWebChannel: Failed to get completed matches: {e}"
)
return
json
.
dumps
([])
def
_get_license_text_from_database
(
self
)
->
str
:
"""Get license text from database configuration"""
try
:
if
not
self
.
db_manager
:
logger
.
error
(
"Database manager not available for getting license text"
)
return
"License text not available - database not connected"
# Get license text from configuration
license_text
=
self
.
db_manager
.
get_config_value
(
'license_text'
,
'License text not configured'
)
logger
.
debug
(
f
"Retrieved license text from database: {license_text}"
)
return
license_text
except
Exception
as
e
:
logger
.
error
(
f
"Failed to get license text from database: {e}"
)
return
"License text not available - database error"
def
_get_completed_matches_from_database
(
self
)
->
Optional
[
List
[
Dict
[
str
,
Any
]]]:
"""Get last 3 completed matches from database"""
try
:
from
..database.models
import
MatchModel
from
datetime
import
datetime
# Use the database manager passed to this channel
if
not
self
.
db_manager
:
logger
.
error
(
"Database manager not initialized"
)
return
[]
session
=
self
.
db_manager
.
get_session
()
try
:
# Get last 3 completed matches (status = 'done' and result is not null)
# Ordered by end_time descending (most recent first)
completed_matches
=
session
.
query
(
MatchModel
)
.
filter
(
MatchModel
.
status
==
'done'
,
MatchModel
.
result
.
isnot
(
None
),
MatchModel
.
end_time
.
isnot
(
None
)
)
.
order_by
(
MatchModel
.
end_time
.
desc
())
.
limit
(
3
)
.
all
()
if
not
completed_matches
:
logger
.
debug
(
"No completed matches found"
)
return
[]
matches_data
=
[]
for
match
in
completed_matches
:
match_data
=
{
'id'
:
match
.
id
,
'match_number'
:
match
.
match_number
,
'fighter1_township'
:
match
.
fighter1_township
,
'fighter2_township'
:
match
.
fighter2_township
,
'venue_kampala_township'
:
match
.
venue_kampala_township
,
'result'
:
match
.
result
,
'under_over_result'
:
match
.
under_over_result
,
'end_time'
:
match
.
end_time
.
isoformat
()
if
match
.
end_time
else
None
}
matches_data
.
append
(
match_data
)
logger
.
debug
(
f
"Retrieved {len(matches_data)} completed matches from database"
)
return
matches_data
finally
:
session
.
close
()
except
Exception
as
e
:
logger
.
error
(
f
"Failed to get completed matches from database: {e}"
)
return
[]
def
_get_fixture_data_from_games_thread
(
self
)
->
Optional
[
List
[
Dict
[
str
,
Any
]]]:
def
_get_fixture_data_from_games_thread
(
self
)
->
Optional
[
List
[
Dict
[
str
,
Any
]]]:
"""Get fixture data from the games thread"""
"""Get fixture data from the games thread"""
try
:
try
:
...
...
mbetterclient/qt_player/templates/default.html
View file @
1f2b9534
...
@@ -256,26 +256,42 @@
...
@@ -256,26 +256,42 @@
let
currentMessage
=
'Waiting for game to start...'
;
let
currentMessage
=
'Waiting for game to start...'
;
let
currentIcon
=
'🥊'
;
let
currentIcon
=
'🥊'
;
let
licenseText
=
'Loading license text...'
;
let
licenseText
=
'Loading license text...'
;
let
licenseTextFromData
=
''
;
// 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 text overlay data:'
,
data
);
console
.
log
(
'Received text overlay data:'
,
data
);
overlayData
=
data
||
{};
overlayData
=
data
||
{};
if
(
data
&&
data
.
title
)
{
let
contentChanged
=
false
;
if
(
data
&&
data
.
title
&&
data
.
title
!==
currentTitle
)
{
currentTitle
=
data
.
title
;
currentTitle
=
data
.
title
;
contentChanged
=
true
;
}
}
if
(
data
&&
data
.
message
)
{
if
(
data
&&
data
.
message
&&
data
.
message
!==
currentMessage
)
{
currentMessage
=
data
.
message
;
currentMessage
=
data
.
message
;
contentChanged
=
true
;
}
}
if
(
data
&&
data
.
icon
)
{
if
(
data
&&
data
.
icon
&&
data
.
icon
!==
currentIcon
)
{
currentIcon
=
data
.
icon
;
currentIcon
=
data
.
icon
;
contentChanged
=
true
;
}
// Handle license text from overlay data
if
(
data
&&
data
.
license_text
)
{
licenseTextFromData
=
data
.
license_text
;
licenseText
=
licenseTextFromData
;
updateLicenseDisplay
();
}
}
// Only update message display and restart animations if content actually changed
if
(
contentChanged
)
{
updateMessageDisplay
();
updateMessageDisplay
();
}
}
}
// Update the message display
// Update the message display
function
updateMessageDisplay
()
{
function
updateMessageDisplay
()
{
...
@@ -292,21 +308,35 @@
...
@@ -292,21 +308,35 @@
restartAnimations
();
restartAnimations
();
}
}
// Fetch license text from
API
// Fetch license text from
WebChannel
async
function
fetchLicenseText
()
{
async
function
fetchLicenseText
()
{
try
{
try
{
// Try to fetch from the web dashboard API
// Only fetch from WebChannel if we don't have license text from overlay data yet
const
response
=
await
fetch
(
'http://127.0.0.1:5001/api/config/license-text'
);
if
(
!
licenseTextFromData
||
licenseTextFromData
.
trim
()
===
''
)
{
if
(
response
.
ok
)
{
// Try to get license text from Qt WebChannel
const
data
=
await
response
.
json
();
if
(
window
.
overlay
&&
window
.
overlay
.
getLicenseText
)
{
if
(
data
.
success
)
{
const
licenseTextData
=
await
window
.
overlay
.
getLicenseText
();
licenseText
=
data
.
license_text
||
''
;
if
(
licenseTextData
)
{
// Parse the JSON response to extract license_text
try
{
const
licenseData
=
JSON
.
parse
(
licenseTextData
);
if
(
licenseData
.
license_text
)
{
licenseText
=
licenseData
.
license_text
;
updateLicenseDisplay
();
updateLicenseDisplay
();
console
.
log
(
'License text loaded from WebChannel:'
,
licenseText
);
}
else
{
console
.
log
(
'No license_text found in WebChannel response'
);
}
}
catch
(
parseError
)
{
console
.
log
(
'Failed to parse license text JSON from WebChannel:'
,
parseError
);
// Keep default text if parsing fails
}
}
}
}
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
'Could not fetch license text from
API
, using default'
);
console
.
log
(
'Could not fetch license text from
WebChannel
, using default'
);
// Keep default text if
API
is not available
// Keep default text if
WebChannel
is not available
}
}
}
}
...
@@ -347,28 +377,79 @@
...
@@ -347,28 +377,79 @@
document
.
addEventListener
(
'DOMContentLoaded'
,
function
()
{
document
.
addEventListener
(
'DOMContentLoaded'
,
function
()
{
console
.
log
(
'Text message overlay initialized'
);
console
.
log
(
'Text message overlay initialized'
);
updateMessageDisplay
();
updateMessageDisplay
();
fetchLicenseText
();
// Setup WebChannel communication
setupWebChannel
();
});
});
// Qt WebChannel initialization (when available)
// Setup WebChannel communication
if
(
typeof
QWebChannel
!==
'undefined'
)
{
function
setupWebChannel
()
{
new
QWebChannel
(
qt
.
webChannelTransport
,
function
(
channel
)
{
// Check if WebChannel is already set up by overlay.js
console
.
log
(
'WebChannel initialized for text message overlay'
);
if
(
window
.
overlay
)
{
console
.
log
(
'WebChannel already set up by overlay.js'
);
// Connect to overlay object if available
// Listen for data updates from Python
if
(
channel
.
objects
.
overlay
)
{
if
(
window
.
overlay
.
dataUpdated
)
{
channel
.
objects
.
overlay
.
dataChanged
.
connect
(
function
(
data
)
{
window
.
overlay
.
dataUpdated
.
connect
(
function
(
data
)
{
console
.
log
(
'Received data update from Python:'
,
data
);
updateOverlayData
(
data
);
updateOverlayData
(
data
);
});
});
}
// Get initial data
// Wait for WebChannel to be ready before fetching license text
if
(
channel
.
objects
.
overlay
.
getCurrentData
)
{
waitForWebChannelReady
(()
=>
{
channel
.
objects
.
overlay
.
getCurrentData
(
function
(
data
)
{
fetchLicenseText
();
// Fetch license text now that WebChannel is ready
updateOverlayData
(
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
(
'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
(
'Received data update from Python (fallback):'
,
data
);
updateOverlayData
(
data
);
});
}
}
// Wait for WebChannel to be ready before fetching license text
waitForWebChannelReady
(()
=>
{
fetchLicenseText
();
// Fetch license text now that WebChannel is ready
});
});
});
}
catch
(
e
)
{
console
.
log
(
'Failed to setup WebChannel:'
,
e
);
}
}
else
{
console
.
log
(
'WebChannel not available, using default settings'
);
}
}
// Wait for WebChannel to be ready
function
waitForWebChannelReady
(
callback
,
maxWait
=
10000
)
{
const
startTime
=
Date
.
now
();
const
checkReady
=
()
=>
{
if
(
window
.
overlay
&&
window
.
overlay
.
getLicenseText
)
{
console
.
log
(
'WebChannel ready for license text fetch'
);
callback
();
}
else
if
(
Date
.
now
()
-
startTime
>
maxWait
)
{
console
.
warn
(
'WebChannel not ready after max wait time, proceeding anyway'
);
callback
();
}
else
{
setTimeout
(
checkReady
,
100
);
}
};
checkReady
();
}
}
// Export functions for external use
// Export functions for external use
...
@@ -377,7 +458,7 @@
...
@@ -377,7 +458,7 @@
</script>
</script>
<!--
<!--
IMPORTANT: When creating or editing custom templates, always maintain these
two
script tags:
IMPORTANT: When creating or editing custom templates, always maintain these script tags:
1. qrc:///qtwebchannel/qwebchannel.js - Required for Qt WebChannel communication
1. qrc:///qtwebchannel/qwebchannel.js - Required for Qt WebChannel communication
2. overlay://overlay.js - Required for overlay functionality and data updates
2. overlay://overlay.js - Required for overlay functionality and data updates
...
...
mbetterclient/qt_player/templates/fixtures.html
View file @
1f2b9534
...
@@ -143,32 +143,23 @@
...
@@ -143,32 +143,23 @@
.results-bottom-bar
{
.results-bottom-bar
{
position
:
absolute
;
position
:
absolute
;
bottom
:
20px
;
bottom
:
20px
;
left
:
50%
;
left
:
20px
;
transform
:
translateX
(
-50%
)
;
right
:
20px
;
background
:
rgba
(
0
,
123
,
255
,
0.85
);
background
:
rgba
(
0
,
123
,
255
,
0.85
);
border-radius
:
15px
;
border-radius
:
15px
;
padding
:
15px
20px
;
padding
:
15px
20px
;
max-width
:
90%
;
box-shadow
:
0
4px
16px
rgba
(
0
,
0
,
0
,
0.3
);
box-shadow
:
0
4px
16px
rgba
(
0
,
0
,
0
,
0.3
);
backdrop-filter
:
blur
(
10px
);
backdrop-filter
:
blur
(
10px
);
border
:
2px
solid
rgba
(
255
,
255
,
255
,
0.1
);
border
:
2px
solid
rgba
(
255
,
255
,
255
,
0.1
);
color
:
white
;
color
:
white
;
font-size
:
24px
;
font-size
:
24px
;
text-align
:
left
;
text-align
:
center
;
z-index
:
1001
;
z-index
:
1001
;
white-space
:
nowrap
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
}
}
.results-title
{
font-weight
:
bold
;
margin-bottom
:
10px
;
text-shadow
:
1px
1px
2px
rgba
(
0
,
0
,
0
,
0.5
);
}
.match-result
{
font-size
:
20px
;
margin
:
5px
0
;
text-shadow
:
1px
1px
2px
rgba
(
0
,
0
,
0
,
0.5
);
}
.fixtures-title
{
.fixtures-title
{
color
:
white
;
color
:
white
;
...
@@ -417,7 +408,6 @@
...
@@ -417,7 +408,6 @@
<!-- Results Bottom Bar -->
<!-- Results Bottom Bar -->
<div
class=
"results-bottom-bar"
id=
"resultsBottomBar"
style=
"display: none;"
>
<div
class=
"results-bottom-bar"
id=
"resultsBottomBar"
style=
"display: none;"
>
<div
class=
"results-title"
>
RESULTS of the last 3 matches:
</div>
<div
id=
"resultsContent"
>
<div
id=
"resultsContent"
>
<!-- Match results will be populated by JavaScript -->
<!-- Match results will be populated by JavaScript -->
</div>
</div>
...
@@ -822,21 +812,32 @@
...
@@ -822,21 +812,32 @@
];
];
}
}
// Fetch license text from
API
// Fetch license text from
WebChannel
async
function
fetchLicenseText
()
{
async
function
fetchLicenseText
()
{
try
{
try
{
// Try to fetch from the web dashboard API
// Try to get license text from Qt WebChannel
const
response
=
await
fetch
(
'http://127.0.0.1:5001/api/config/license-text'
);
if
(
window
.
overlay
&&
window
.
overlay
.
getLicenseText
)
{
if
(
response
.
ok
)
{
const
licenseTextData
=
await
window
.
overlay
.
getLicenseText
();
const
data
=
await
response
.
json
();
if
(
licenseTextData
)
{
if
(
data
.
success
)
{
// Parse the JSON response to extract license_text
licenseText
=
data
.
license_text
||
''
;
try
{
const
licenseData
=
JSON
.
parse
(
licenseTextData
);
if
(
licenseData
.
license_text
)
{
licenseText
=
licenseData
.
license_text
;
updateLicenseDisplay
();
updateLicenseDisplay
();
console
.
log
(
'License text loaded from WebChannel:'
,
licenseText
);
}
else
{
console
.
log
(
'No license_text found in WebChannel response'
);
}
}
catch
(
parseError
)
{
console
.
log
(
'Failed to parse license text JSON from WebChannel:'
,
parseError
);
// Keep default text if parsing fails
}
}
}
}
}
}
catch
(
error
)
{
}
catch
(
error
)
{
console
.
log
(
'Could not fetch license text from
API
, using default'
);
console
.
log
(
'Could not fetch license text from
WebChannel
, using default'
);
// Keep default text if
API
is not available
// Keep default text if
WebChannel
is not available
}
}
}
}
...
@@ -1090,7 +1091,19 @@
...
@@ -1090,7 +1091,19 @@
try {
try {
debugTime('Fetching last match results');
debugTime('Fetching last match results');
// Try to fetch from web API if webServerBaseUrl is available
// Try WebChannel first (same as license text)
if (window.overlay && typeof window.overlay.getCompletedMatches === 'function') {
const completedMatchesJson = await window.overlay.getCompletedMatches();
const completedMatches = JSON.parse(completedMatchesJson);
if (completedMatches && completedMatches.length > 0) {
// Take last 3 matches (already ordered by end_time desc in WebChannel)
const lastMatches = completedMatches.slice(0, 3);
renderMatchResults(lastMatches);
return;
}
}
// Fallback: try to fetch from web API if webServerBaseUrl is available
if (webServerBaseUrl) {
if (webServerBaseUrl) {
const response = await fetch(`
$
{
webServerBaseUrl
}
/api/fixtures`
);
const response = await fetch(`
$
{
webServerBaseUrl
}
/api/fixtures`
);
if
(
response
.
ok
)
{
if
(
response
.
ok
)
{
...
@@ -1125,17 +1138,6 @@
...
@@ -1125,17 +1138,6 @@
}
}
}
}
// Fallback: try WebChannel if available
if
(
window
.
overlay
&&
typeof
window
.
overlay
.
getCompletedMatches
===
'function'
)
{
const
completedMatchesJson
=
await
window
.
overlay
.
getCompletedMatches
();
const
completedMatches
=
JSON
.
parse
(
completedMatchesJson
);
if
(
completedMatches
&&
completedMatches
.
length
>
0
)
{
const
lastMatches
=
completedMatches
.
slice
(
-
3
);
// Last 3 matches
renderMatchResults
(
lastMatches
);
return
;
}
}
// No results available
// No results available
debugTime
(
'No match results available'
);
debugTime
(
'No match results available'
);
document
.
getElementById
(
'resultsBottomBar'
).
style
.
display
=
'none'
;
document
.
getElementById
(
'resultsBottomBar'
).
style
.
display
=
'none'
;
...
@@ -1151,9 +1153,9 @@
...
@@ -1151,9 +1153,9 @@
const
resultsContent
=
document
.
getElementById
(
'resultsContent'
);
const
resultsContent
=
document
.
getElementById
(
'resultsContent'
);
if
(
!
resultsContent
)
return
;
if
(
!
resultsContent
)
return
;
let
results
HTML
=
'
'
;
let
results
Text
=
'RESULTS:
'
;
matches
.
forEach
(
match
=>
{
matches
.
forEach
(
(
match
,
index
)
=>
{
const
matchNumber
=
match
.
match_number
||
match
.
id
||
'N/A'
;
const
matchNumber
=
match
.
match_number
||
match
.
id
||
'N/A'
;
const
fighter1
=
match
.
fighter1_township
||
match
.
fighter1
||
'Fighter 1'
;
const
fighter1
=
match
.
fighter1_township
||
match
.
fighter1
||
'Fighter 1'
;
const
fighter2
=
match
.
fighter2_township
||
match
.
fighter2
||
'Fighter 2'
;
const
fighter2
=
match
.
fighter2_township
||
match
.
fighter2
||
'Fighter 2'
;
...
@@ -1162,10 +1164,13 @@
...
@@ -1162,10 +1164,13 @@
const
resultText
=
underOver
?
`
${
result
}
(
${
underOver
}
)`
:
result
;
const
resultText
=
underOver
?
`
${
result
}
(
${
underOver
}
)`
:
result
;
resultsHTML
+=
`<div class="match-result">Match #
${
matchNumber
}
::
${
fighter1
}
vs
${
fighter2
}
:
${
resultText
}
</div>`
;
resultsText
+=
`Match #
${
matchNumber
}
:
${
fighter1
}
vs
${
fighter2
}
=
${
resultText
}
`
;
if
(
index
<
matches
.
length
-
1
)
{
resultsText
+=
' | '
;
}
});
});
resultsContent
.
innerHTML
=
resultsHTML
;
resultsContent
.
textContent
=
resultsText
;
document
.
getElementById
(
'resultsBottomBar'
).
style
.
display
=
'block'
;
document
.
getElementById
(
'resultsBottomBar'
).
style
.
display
=
'block'
;
debugTime
(
`Rendered
${
matches
.
length
}
match results`
);
debugTime
(
`Rendered
${
matches
.
length
}
match results`
);
...
@@ -1179,9 +1184,6 @@
...
@@ -1179,9 +1184,6 @@
// Setup WebChannel first
// Setup WebChannel first
setupWebChannel
();
setupWebChannel
();
// Fetch license text
fetchLicenseText
();
// 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'
;
...
@@ -1190,9 +1192,12 @@
...
@@ -1190,9 +1192,12 @@
debugTime
(
'UI initialized - Loading message displayed'
);
debugTime
(
'UI initialized - Loading message displayed'
);
// Wait briefly for WebChannel to connect
// Wait for WebChannel to be ready before fetching data
setTimeout
(()
=>
{
waitForWebChannelReady
(()
=>
{
console
.
log
(
'🔍 DEBUG: Starting fixture data fetch via WebChannel'
);
console
.
log
(
'🔍 DEBUG: WebChannel ready, starting data fetch'
);
// Fetch license text now that WebChannel is ready
fetchLicenseText
();
// Fetch fixtures data via WebChannel
// Fetch fixtures data via WebChannel
debugTime
(
'Fetching fixtures data via WebChannel'
);
debugTime
(
'Fetching fixtures data via WebChannel'
);
...
@@ -1213,8 +1218,27 @@
...
@@ -1213,8 +1218,27 @@
debugTime
(
'Data was received before 5 second timeout'
);
debugTime
(
'Data was received before 5 second timeout'
);
}
}
},
5000
);
},
5000
);
},
50
);
// Wait 50ms for WebChannel setup
});
});
});
// Wait for WebChannel to be ready
function
waitForWebChannelReady
(
callback
,
maxWait
=
10000
)
{
const
startTime
=
Date
.
now
();
const
checkReady
=
()
=>
{
if
(
window
.
overlay
&&
window
.
overlay
.
getLicenseText
)
{
console
.
log
(
'🔍 DEBUG: WebChannel ready for license text fetch'
);
callback
();
}
else
if
(
Date
.
now
()
-
startTime
>
maxWait
)
{
console
.
warn
(
'🔍 DEBUG: WebChannel not ready after max wait time, proceeding anyway'
);
callback
();
}
else
{
setTimeout
(
checkReady
,
100
);
}
};
checkReady
();
}
</script>
</script>
...
...
mbetterclient/qt_player/templates/match.html
View file @
1f2b9534
This diff is collapsed.
Click to expand it.
mbetterclient/qt_player/templates/text.html
View file @
1f2b9534
...
@@ -19,6 +19,31 @@
...
@@ -19,6 +19,31 @@
position
:
relative
;
position
:
relative
;
}
}
/* License Top Bar */
.license-bar
{
position
:
absolute
;
top
:
0
;
left
:
0
;
right
:
0
;
background
:
rgba
(
0
,
123
,
255
,
0.40
);
border-radius
:
0
0
20px
20px
;
padding
:
15px
30px
;
text-align
:
center
;
z-index
:
1000
;
backdrop-filter
:
blur
(
10px
);
border
:
2px
solid
rgba
(
255
,
255
,
255
,
0.2
);
border-top
:
none
;
}
.license-text
{
color
:
rgba
(
255
,
255
,
255
,
0.95
);
font-size
:
16px
;
font-weight
:
bold
;
text-shadow
:
2px
2px
4px
rgba
(
0
,
0
,
0
,
0.6
);
line-height
:
1.4
;
word-wrap
:
break-word
;
}
/* Debug indicator to verify CSS is loaded */
/* Debug indicator to verify CSS is loaded */
body
::before
{
body
::before
{
content
:
'Text Message Overlay v1.0 loaded'
;
content
:
'Text Message Overlay v1.0 loaded'
;
...
@@ -211,6 +236,11 @@
...
@@ -211,6 +236,11 @@
</style>
</style>
</head>
</head>
<body>
<body>
<!-- License Top Bar -->
<div
class=
"license-bar"
id=
"licenseBar"
>
<div
class=
"license-text"
id=
"licenseText"
>
Loading license text...
</div>
</div>
<div
class=
"overlay-container"
>
<div
class=
"overlay-container"
>
<div
class=
"message-panel"
id=
"messagePanel"
>
<div
class=
"message-panel"
id=
"messagePanel"
>
<div
class=
"message-icon"
id=
"messageIcon"
>
📢
</div>
<div
class=
"message-icon"
id=
"messageIcon"
>
📢
</div>
...
@@ -225,26 +255,90 @@
...
@@ -225,26 +255,90 @@
let
currentTitle
=
'Announcement'
;
let
currentTitle
=
'Announcement'
;
let
currentMessage
=
'This is a custom message from the system.'
;
let
currentMessage
=
'This is a custom message from the system.'
;
let
currentIcon
=
'📢'
;
let
currentIcon
=
'📢'
;
let
licenseText
=
'Loading license text...'
;
let
licenseTextFromData
=
''
;
// 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 text overlay data:'
,
data
);
console
.
log
(
'Received text overlay data:'
,
data
);
overlayData
=
data
||
{};
overlayData
=
data
||
{};
if
(
data
&&
data
.
title
)
{
let
contentChanged
=
false
;
if
(
data
&&
data
.
title
&&
data
.
title
!==
currentTitle
)
{
currentTitle
=
data
.
title
;
currentTitle
=
data
.
title
;
contentChanged
=
true
;
}
}
if
(
data
&&
data
.
message
)
{
if
(
data
&&
data
.
message
&&
data
.
message
!==
currentMessage
)
{
currentMessage
=
data
.
message
;
currentMessage
=
data
.
message
;
contentChanged
=
true
;
}
}
if
(
data
&&
data
.
icon
)
{
if
(
data
&&
data
.
icon
&&
data
.
icon
!==
currentIcon
)
{
currentIcon
=
data
.
icon
;
currentIcon
=
data
.
icon
;
contentChanged
=
true
;
}
// Handle license text from overlay data
if
(
data
&&
data
.
license_text
)
{
licenseTextFromData
=
data
.
license_text
;
licenseText
=
licenseTextFromData
;
updateLicenseDisplay
();
}
}
// Only update message display and restart animations if content actually changed
if
(
contentChanged
)
{
updateMessageDisplay
();
updateMessageDisplay
();
}
}
}
// Fetch license text from WebChannel
async
function
fetchLicenseText
()
{
try
{
// Only fetch from WebChannel if we don't have license text from overlay data yet
if
(
!
licenseTextFromData
||
licenseTextFromData
.
trim
()
===
''
)
{
// Try to get license text from Qt WebChannel
if
(
window
.
overlay
&&
window
.
overlay
.
getLicenseText
)
{
const
licenseTextData
=
await
window
.
overlay
.
getLicenseText
();
if
(
licenseTextData
)
{
// Parse the JSON response to extract license_text
try
{
const
licenseData
=
JSON
.
parse
(
licenseTextData
);
if
(
licenseData
.
license_text
)
{
licenseText
=
licenseData
.
license_text
;
updateLicenseDisplay
();
console
.
log
(
'License text loaded from WebChannel:'
,
licenseText
);
}
else
{
console
.
log
(
'No license_text found in WebChannel response'
);
}
}
catch
(
parseError
)
{
console
.
log
(
'Failed to parse license text JSON from WebChannel:'
,
parseError
);
// Keep default text if parsing fails
}
}
}
}
}
catch
(
error
)
{
console
.
log
(
'Could not fetch license text from WebChannel, using default'
);
// Keep default text if WebChannel is not available
}
}
// Update license text display
function
updateLicenseDisplay
()
{
const
licenseBar
=
document
.
getElementById
(
'licenseBar'
);
const
licenseElement
=
document
.
getElementById
(
'licenseText'
);
if
(
licenseElement
&&
licenseBar
)
{
if
(
licenseText
&&
licenseText
.
trim
()
!==
''
)
{
licenseElement
.
textContent
=
licenseText
;
licenseBar
.
style
.
display
=
'block'
;
}
else
{
licenseBar
.
style
.
display
=
'none'
;
}
}
}
// Update the message display
// Update the message display
function
updateMessageDisplay
()
{
function
updateMessageDisplay
()
{
...
@@ -283,27 +377,79 @@
...
@@ -283,27 +377,79 @@
document
.
addEventListener
(
'DOMContentLoaded'
,
function
()
{
document
.
addEventListener
(
'DOMContentLoaded'
,
function
()
{
console
.
log
(
'Text message overlay initialized'
);
console
.
log
(
'Text message overlay initialized'
);
updateMessageDisplay
();
updateMessageDisplay
();
// Setup WebChannel communication
setupWebChannel
();
});
});
// Qt WebChannel initialization (when available)
// Setup WebChannel communication
if
(
typeof
QWebChannel
!==
'undefined'
)
{
function
setupWebChannel
()
{
new
QWebChannel
(
qt
.
webChannelTransport
,
function
(
channel
)
{
// Check if WebChannel is already set up by overlay.js
console
.
log
(
'WebChannel initialized for text message overlay'
);
if
(
window
.
overlay
)
{
console
.
log
(
'WebChannel already set up by overlay.js'
);
// Connect to overlay object if available
// Listen for data updates from Python
if
(
channel
.
objects
.
overlay
)
{
if
(
window
.
overlay
.
dataUpdated
)
{
channel
.
objects
.
overlay
.
dataChanged
.
connect
(
function
(
data
)
{
window
.
overlay
.
dataUpdated
.
connect
(
function
(
data
)
{
console
.
log
(
'Received data update from Python:'
,
data
);
updateOverlayData
(
data
);
updateOverlayData
(
data
);
});
});
}
// Get initial data
// Wait for WebChannel to be ready before fetching license text
if
(
channel
.
objects
.
overlay
.
getCurrentData
)
{
waitForWebChannelReady
(()
=>
{
channel
.
objects
.
overlay
.
getCurrentData
(
function
(
data
)
{
fetchLicenseText
();
// Fetch license text now that WebChannel is ready
updateOverlayData
(
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
(
'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
(
'Received data update from Python (fallback):'
,
data
);
updateOverlayData
(
data
);
});
}
}
// Wait for WebChannel to be ready before fetching license text
waitForWebChannelReady
(()
=>
{
fetchLicenseText
();
// Fetch license text now that WebChannel is ready
});
});
});
}
catch
(
e
)
{
console
.
log
(
'Failed to setup WebChannel:'
,
e
);
}
}
else
{
console
.
log
(
'WebChannel not available, using default settings'
);
}
}
// Wait for WebChannel to be ready
function
waitForWebChannelReady
(
callback
,
maxWait
=
10000
)
{
const
startTime
=
Date
.
now
();
const
checkReady
=
()
=>
{
if
(
window
.
overlay
&&
window
.
overlay
.
getLicenseText
)
{
console
.
log
(
'WebChannel ready for license text fetch'
);
callback
();
}
else
if
(
Date
.
now
()
-
startTime
>
maxWait
)
{
console
.
warn
(
'WebChannel not ready after max wait time, proceeding anyway'
);
callback
();
}
else
{
setTimeout
(
checkReady
,
100
);
}
};
checkReady
();
}
}
// Export functions for external use
// Export functions for external use
...
@@ -312,7 +458,7 @@
...
@@ -312,7 +458,7 @@
</script>
</script>
<!--
<!--
IMPORTANT: When creating or editing custom templates, always maintain these
two
script tags:
IMPORTANT: When creating or editing custom templates, always maintain these script tags:
1. qrc:///qtwebchannel/qwebchannel.js - Required for Qt WebChannel communication
1. qrc:///qtwebchannel/qwebchannel.js - Required for Qt WebChannel communication
2. overlay://overlay.js - Required for overlay functionality and data updates
2. overlay://overlay.js - Required for overlay functionality and data updates
...
...
test_api.py
deleted
100644 → 0
View file @
0a38c586
#!/usr/bin/env python3
"""
Test script to check API endpoints for debugging fixtures overlay
"""
import
requests
import
json
import
sys
from
pathlib
import
Path
def
test_fixtures_api
():
"""Test the fixtures API endpoint"""
print
(
"Testing fixtures API endpoint..."
)
# Try different possible URLs
urls_to_test
=
[
"http://127.0.0.1:5001/api/fixtures"
,
"http://localhost:5001/api/fixtures"
,
"http://127.0.0.1:5000/api/fixtures"
,
"http://localhost:5000/api/fixtures"
]
for
url
in
urls_to_test
:
print
(
f
"
\n
Trying URL: {url}"
)
try
:
response
=
requests
.
get
(
url
,
timeout
=
5
)
print
(
f
"Status Code: {response.status_code}"
)
if
response
.
status_code
==
200
:
try
:
data
=
response
.
json
()
print
(
"Response data:"
)
print
(
json
.
dumps
(
data
,
indent
=
2
))
if
'success'
in
data
and
data
[
'success'
]:
print
(
f
"✅ SUCCESS: Found {data.get('total', 0)} fixtures"
)
return
True
else
:
print
(
"❌ API returned success=false"
)
return
False
except
json
.
JSONDecodeError
as
e
:
print
(
f
"❌ Invalid JSON response: {e}"
)
print
(
f
"Raw response: {response.text[:500]}..."
)
return
False
else
:
print
(
f
"❌ HTTP Error: {response.status_code}"
)
print
(
f
"Response: {response.text[:200]}..."
)
except
requests
.
exceptions
.
ConnectionError
:
print
(
"❌ Connection refused - server not running"
)
except
requests
.
exceptions
.
Timeout
:
print
(
"❌ Request timed out"
)
except
Exception
as
e
:
print
(
f
"❌ Error: {e}"
)
print
(
"
\n
❌ All URLs failed - API server may not be running"
)
return
False
def
test_web_dashboard_status
():
"""Test if web dashboard is running"""
print
(
"
\n
Testing web dashboard status..."
)
urls_to_test
=
[
"http://127.0.0.1:5001/"
,
"http://localhost:5001/"
,
"http://127.0.0.1:5000/"
,
"http://localhost:5000/"
]
for
url
in
urls_to_test
:
print
(
f
"Trying URL: {url}"
)
try
:
response
=
requests
.
get
(
url
,
timeout
=
5
)
print
(
f
"Status Code: {response.status_code}"
)
if
response
.
status_code
==
200
:
print
(
"✅ Web dashboard is running"
)
return
True
except
Exception
as
e
:
print
(
f
"❌ Error: {e}"
)
print
(
"❌ Web dashboard not accessible"
)
return
False
def
main
():
print
(
"=== MbetterClient API Test ==="
)
# Test web dashboard first
web_running
=
test_web_dashboard_status
()
if
not
web_running
:
print
(
"
\n
⚠️ Web dashboard is not running. Make sure to start the web server first."
)
print
(
"Run: python main.py --web-only"
)
sys
.
exit
(
1
)
# Test fixtures API
api_working
=
test_fixtures_api
()
if
api_working
:
print
(
"
\n
✅ API test completed successfully"
)
else
:
print
(
"
\n
❌ API test failed"
)
print
(
"
\n
Troubleshooting tips:"
)
print
(
"1. Make sure the web server is running"
)
print
(
"2. Check if the database has fixture data"
)
print
(
"3. Check the web server logs for errors"
)
print
(
"4. Verify the fixtures endpoint is properly configured"
)
if
__name__
==
"__main__"
:
main
()
\ No newline at end of file
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