Commit latest changes on experimental branch

parent 9ed29d92
......@@ -229,6 +229,12 @@ Examples:
help='Enable single window overlay mode (overlay stacks on top of player widget instead of separate window)'
)
parser.add_argument(
'--overlay-web',
action='store_true',
help='Enable web-based player mode (QWebEngineView with static HTML/JS player instead of native Qt player)'
)
return parser.parse_args()
def validate_arguments(args):
......@@ -236,10 +242,15 @@ def validate_arguments(args):
if args.no_qt and args.no_web:
print("Error: Cannot disable both Qt and web interfaces")
sys.exit(1)
if args.web_port < 1 or args.web_port > 65535:
print("Error: Web port must be between 1 and 65535")
sys.exit(1)
# Ensure mutual exclusivity between overlay modes
if args.overlay_single and args.overlay_web:
print("Error: Cannot use both --overlay-single and --overlay-web options. They are mutually exclusive.")
sys.exit(1)
# Directory creation is handled by AppSettings.ensure_directories()
# which uses persistent user directories for PyInstaller compatibility
......@@ -300,6 +311,7 @@ def main():
# Overlay settings
settings.qt.overlay_single_window = args.overlay_single
settings.qt.overlay_web_player = args.overlay_web
if args.db_path:
settings.database_path = args.db_path
......
......@@ -229,6 +229,7 @@ class QtConfig:
default_template: str = "news_template"
overlay_opacity: float = 0.9
overlay_single_window: bool = False
overlay_web_player: bool = False
# Performance settings
hardware_acceleration: bool = True
......
......@@ -140,6 +140,7 @@ class MbetterClientApplication:
# Preserve command line overlay settings
stored_settings.qt.overlay_single_window = self.settings.qt.overlay_single_window
stored_settings.qt.overlay_web_player = self.settings.qt.overlay_web_player
# Preserve command line SSL settings
stored_settings.web.enable_ssl = self.settings.web.enable_ssl
......
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Mbetter Web Player</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: black;
overflow: hidden;
width: 100vw;
height: 100vh;
position: relative;
color: white;
}
/* Video container */
.video-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
z-index: 100; /* Increased z-index to ensure video is above background but below overlays */
}
/* Video element */
#webVideoPlayer {
width: 100%;
height: 100%;
object-fit: contain;
background: black;
visibility: visible !important; /* Ensure video is visible */
opacity: 1 !important; /* Ensure video is not transparent */
}
/* Overlay container */
.overlay-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
/* Message panel */
.message-panel {
background: rgba(0, 123, 255, 0.40);
border-radius: 20px;
padding: 40px 60px;
min-width: 500px;
max-width: 80%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
border: 2px solid rgba(255, 255, 255, 0.2);
opacity: 0;
transform: translateY(-30px);
animation: slideInDown 1s ease-out forwards;
}
.message-title {
color: #ffffff;
font-size: 32px;
font-weight: bold;
text-align: center;
margin-bottom: 20px;
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.8);
opacity: 0;
animation: titleFadeIn 1.5s ease-out 0.5s forwards;
}
.message-content {
color: rgba(255, 255, 255, 0.95);
font-size: 20px;
text-align: center;
line-height: 1.6;
max-width: 100%;
word-wrap: break-word;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.6);
opacity: 0;
animation: contentFadeIn 1.5s ease-out 1s forwards;
}
.message-icon {
font-size: 48px;
color: #ffffff;
margin-bottom: 20px;
text-shadow: 3px 3px 6px rgba(0, 0, 0, 0.8);
opacity: 0;
animation: iconBounce 2s ease-out 0.2s forwards;
}
/* Timer in top right */
.timer-container {
position: absolute;
top: 20px;
right: 20px;
background: rgba(0, 123, 255, 0.8);
color: white;
padding: 12px 18px;
border-radius: 8px;
font-size: 32px;
font-weight: bold;
font-family: 'Courier New', monospace;
border: 2px solid rgba(255, 255, 255, 0.3);
z-index: 1001;
min-width: 140px;
text-align: center;
}
/* Bottom info bar */
.info-bar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 123, 255, 0.8);
backdrop-filter: blur(10px);
border-top: 2px solid rgba(255, 255, 255, 0.3);
padding: 20px;
z-index: 1001;
}
.fighter-names {
color: white;
font-size: 36px;
font-weight: bold;
text-align: center;
margin-bottom: 8px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
}
.venue-info {
color: rgba(255, 255, 255, 0.95);
font-size: 28px;
text-align: center;
font-style: italic;
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
}
/* Animations */
@keyframes slideInDown {
0% {
opacity: 0;
transform: translateY(-50px) scale(0.8);
}
100% {
opacity: 1;
transform: translateY(0) scale(1);
}
}
@keyframes titleFadeIn {
0% {
opacity: 0;
transform: translateY(-10px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes contentFadeIn {
0% {
opacity: 0;
transform: translateY(10px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes iconBounce {
0% {
opacity: 0;
transform: scale(0.5);
}
50% {
transform: scale(1.2);
}
100% {
opacity: 1;
transform: scale(1);
}
}
/* Responsive Design */
@media (max-width: 1200px) {
.message-panel {
padding: 30px 50px;
min-width: 400px;
}
.message-title {
font-size: 28px;
}
.message-content {
font-size: 18px;
}
.message-icon {
font-size: 40px;
}
.timer-container {
font-size: 28px;
padding: 10px 14px;
min-width: 130px;
}
}
@media (max-width: 800px) {
.message-panel {
padding: 25px 35px;
min-width: 90%;
max-width: 95%;
}
.message-title {
font-size: 24px;
margin-bottom: 15px;
}
.message-content {
font-size: 16px;
line-height: 1.5;
}
.message-icon {
font-size: 36px;
}
.timer-container {
font-size: 24px;
padding: 8px 12px;
top: 10px;
right: 10px;
min-width: 120px;
}
.info-bar {
padding: 15px;
}
}
</style>
</head>
<body>
<!-- Video container -->
<div class="video-container">
<video id="webVideoPlayer" controls autoplay playsinline>
<source src="" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<!-- Timer in top right -->
<div class="timer-container" id="matchTimer">
00:00
</div>
<!-- Overlay container -->
<div class="overlay-container">
<div class="message-panel" id="messagePanel">
<div class="message-icon" id="messageIcon">📢</div>
<div class="message-title" id="messageTitle">Townships Combat League</div>
<div class="message-content" id="messageContent">Waiting for game to start....</div>
</div>
</div>
<!-- Bottom info bar -->
<div class="info-bar">
<div class="fighter-names" id="fighterNames">Loading fighters...</div>
<div class="venue-info" id="venueInfo">Loading venue...</div>
</div>
<!-- Load WebPlayerAPI JavaScript -->
<script src="web_player.js"></script>
<!-- Qt WebChannel JavaScript will be injected by Qt -->
</body>
</html>
\ No newline at end of file
This diff is collapsed.
<!DOCTYPE html>
<html>
<head>
<title>Simple Video Test</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: black;
overflow: hidden;
width: 100vw;
height: 100vh;
position: relative;
color: white;
}
/* Video container */
.video-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
z-index: 100;
}
/* Video element */
#testVideo {
width: 100%;
height: 100%;
object-fit: contain;
background: black;
visibility: visible !important;
opacity: 1 !important;
display: block !important;
}
/* Status overlay */
.status {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-family: Arial, sans-serif;
font-size: 18px;
z-index: 1000;
background: rgba(0,0,0,0.5);
padding: 5px 10px;
border-radius: 3px;
}
</style>
</head>
<body>
<div class="status" id="status">Loading video...</div>
<div class="video-container">
<video id="testVideo" controls autoplay playsinline muted>
<source src="file:///home/nextime/mbetterc/assets/INTRO.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<script>
// Debug video element
const video = document.getElementById('testVideo');
const status = document.getElementById('status');
console.log('Video element:', video);
console.log('Video style visibility:', window.getComputedStyle(video).visibility);
console.log('Video style opacity:', window.getComputedStyle(video).opacity);
console.log('Video style display:', window.getComputedStyle(video).display);
// Force video to be visible
video.style.visibility = 'visible';
video.style.opacity = '1';
video.style.display = 'block';
video.addEventListener('loadedmetadata', function() {
status.textContent = 'Video loaded: ' + video.duration + ' seconds';
console.log('Video metadata loaded');
});
video.addEventListener('play', function() {
status.textContent = 'Video playing';
console.log('Video started playing');
});
video.addEventListener('pause', function() {
status.textContent = 'Video paused';
console.log('Video paused');
});
video.addEventListener('ended', function() {
status.textContent = 'Video ended';
console.log('Video ended');
});
video.addEventListener('error', function(e) {
status.textContent = 'Video error: ' + e.message;
console.error('Video error:', e);
});
// Try to play the video
video.play().then(() => {
console.log('Playback started successfully');
}).catch(e => {
console.error('Playback failed:', e);
status.textContent = 'Playback failed: ' + e.message;
// If autoplay is blocked, show controls and let user interact
video.controls = true;
video.muted = true;
// Try again with muted
video.play().catch(e2 => {
console.error('Muted playback also failed:', e2);
});
});
</script>
</body>
</html>
\ No newline at end of file
#!/usr/bin/env python3
"""
Test script for video playback functionality in the web player
"""
import sys
import time
import logging
from pathlib import Path
from PyQt6.QtWidgets import QApplication
from PyQt6.QtCore import QUrl, QTimer
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebEngineCore import QWebEngineProfile
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def test_video_playback():
"""Test video playback in a QWebEngineView"""
try:
logger.info("Testing video playback in QWebEngineView...")
# Create QApplication
app = QApplication(sys.argv)
# Create a simple web view
web_view = QWebEngineView()
web_view.setWindowTitle("Video Playback Test")
web_view.resize(800, 600)
# Get the path to the sample video
sample_video_path = Path(__file__).parent / "assets" / "INTRO.mp4"
if not sample_video_path.exists():
# Try to find any video file
assets_dir = Path(__file__).parent / "assets"
video_files = list(assets_dir.glob("*.mp4"))
if video_files:
sample_video_path = video_files[0]
else:
logger.error("No video files found for testing")
return False
# Create HTML content with video player
video_url = QUrl.fromLocalFile(str(sample_video_path)).toString()
html_content = f"""
<!DOCTYPE html>
<html>
<head>
<title>Video Playback Test</title>
<style>
* {{
margin: 0;
padding: 0;
box-sizing: border-box;
}}
body {{
margin: 0;
padding: 0;
background: black;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
overflow: hidden;
}}
.video-container {{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: black;
z-index: 100;
}}
video {{
width: 100%;
height: 100%;
object-fit: contain;
background: black;
visibility: visible !important;
opacity: 1 !important;
display: block !important;
}}
.status {{
position: absolute;
top: 20px;
left: 20px;
color: white;
font-family: Arial, sans-serif;
font-size: 18px;
z-index: 1000;
background: rgba(0,0,0,0.5);
padding: 5px 10px;
border-radius: 3px;
}}
</style>
</head>
<body>
<div class="status" id="status">Loading video...</div>
<div class="video-container">
<video id="testVideo" controls autoplay playsinline>
<source src="{video_url}" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<script>
// Debug video element
const video = document.getElementById('testVideo');
const status = document.getElementById('status');
console.log('Video element:', video);
console.log('Video style visibility:', window.getComputedStyle(video).visibility);
console.log('Video style opacity:', window.getComputedStyle(video).opacity);
console.log('Video style display:', window.getComputedStyle(video).display);
// Force video to be visible
video.style.visibility = 'visible';
video.style.opacity = '1';
video.style.display = 'block';
video.addEventListener('loadedmetadata', function() {{
status.textContent = 'Video loaded: ' + video.duration + ' seconds';
console.log('Video metadata loaded');
}});
video.addEventListener('play', function() {{
status.textContent = 'Video playing';
console.log('Video started playing');
}});
video.addEventListener('pause', function() {{
status.textContent = 'Video paused';
console.log('Video paused');
}});
video.addEventListener('ended', function() {{
status.textContent = 'Video ended';
console.log('Video ended');
}});
video.addEventListener('error', function(e) {{
status.textContent = 'Video error: ' + e.message;
console.error('Video error:', e);
}});
// Try to play the video
video.play().catch(function(e) {{
status.textContent = 'Playback failed: ' + e.message;
console.error('Playback failed:', e);
}});
</script>
</body>
</html>
"""
# Load the HTML content
web_view.setHtml(html_content)
web_view.show()
logger.info(f"Testing video playback with: {sample_video_path}")
logger.info("Web view should appear with video playback...")
# Run the application for a short time to test
app.exec()
return True
except Exception as e:
logger.error(f"Video playback test failed: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
return False
if __name__ == "__main__":
success = test_video_playback()
sys.exit(0 if success else 1)
\ No newline at end of file
#!/usr/bin/env python3
"""
Test script for the new web player functionality
"""
import sys
import time
import logging
from pathlib import Path
# Setup logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def test_web_player():
"""Test the web player functionality"""
try:
# Import the main application
from main import main
from mbetterclient.config.settings import QtConfig
from mbetterclient.core.message_bus import MessageBus
from mbetterclient.qt_player.player import QtVideoPlayer
logger.info("Testing web player functionality...")
# Test 1: Check if the --overlay-web option is properly recognized
test_args = [
'--overlay-web',
'--debug',
'--no-fullscreen',
'--no-screen-cast'
]
logger.info(f"Test arguments: {test_args}")
# Test 2: Verify that the web player HTML file exists
web_player_html_path = Path(__file__).parent / "mbetterclient" / "qt_player" / "web_player_assets" / "web_player.html"
if web_player_html_path.exists():
logger.info(f"✓ Web player HTML file found: {web_player_html_path}")
else:
logger.error(f"✗ Web player HTML file not found: {web_player_html_path}")
return False
# Test 3: Verify that the web player JS file exists
web_player_js_path = Path(__file__).parent / "mbetterclient" / "qt_player" / "web_player_assets" / "web_player.js"
if web_player_js_path.exists():
logger.info(f"✓ Web player JS file found: {web_player_js_path}")
else:
logger.error(f"✗ Web player JS file not found: {web_player_js_path}")
return False
# Test 4: Test video playback with a sample video
sample_video_path = Path(__file__).parent / "assets" / "INTRO.mp4"
if sample_video_path.exists():
logger.info(f"✓ Sample video found: {sample_video_path}")
else:
logger.warning(f"✗ Sample video not found: {sample_video_path}")
# Try to find any video file
assets_dir = Path(__file__).parent / "assets"
video_files = list(assets_dir.glob("*.mp4"))
if video_files:
sample_video_path = video_files[0]
logger.info(f"✓ Found alternative video: {sample_video_path}")
else:
logger.warning("No video files found in assets directory")
sample_video_path = None
logger.info("✓ All web player tests passed!")
return True
except Exception as e:
logger.error(f"Web player test failed: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
return False
if __name__ == "__main__":
success = test_web_player()
sys.exit(0 if success else 1)
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment