removed useless videos

parent 0959c74e
...@@ -2,63 +2,748 @@ ...@@ -2,63 +2,748 @@
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>Video Overlay Test</title> <title>Video Overlay</title>
<style> <style>
html, body { * {
margin: 0; margin: 0;
padding: 0; padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: transparent;
overflow: hidden;
width: 100vw;
height: 100vh;
position: relative;
}
/* Debug indicator to verify CSS is loaded */
body::before {
content: 'Overlay v2.1 loaded';
position: absolute;
top: 5px;
left: 5px;
color: rgba(255,255,255,0.5);
font-size: 10px;
z-index: 9999;
}
.overlay-container {
position: absolute;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
background: rgba(255, 0, 0, 0.5); /* Semi-transparent red to test visibility */ pointer-events: none;
overflow: hidden; z-index: 1000;
} }
.test-overlay { .title-main {
position: absolute; position: absolute;
top: 50%; top: 20%;
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translateX(-50%);
background: rgba(0, 255, 0, 0.9); font-size: 48px;
color: black;
padding: 30px;
font-size: 24px;
font-weight: bold; font-weight: bold;
border: 5px solid yellow; color: white;
text-shadow:
2px 2px 4px rgba(0,0,0,0.8),
-1px -1px 0px rgba(0,0,0,0.5),
1px -1px 0px rgba(0,0,0,0.5),
-1px 1px 0px rgba(0,0,0,0.5),
1px 1px 0px rgba(0,0,0,0.5);
text-align: center;
opacity: 0;
animation: titleSlideIn 2s ease-out forwards;
max-width: 90%;
word-wrap: break-word;
}
.title-subtitle {
position: absolute;
top: 30%;
left: 50%;
transform: translateX(-50%);
font-size: 24px;
color: #ffffff;
text-shadow: 2px 2px 4px rgba(0,0,0,0.7);
text-align: center; text-align: center;
opacity: 0;
animation: titleSlideIn 2s ease-out 0.5s forwards;
max-width: 90%;
}
.news-ticker {
position: absolute;
bottom: 10%;
width: 100%;
background: linear-gradient(90deg,
rgba(220, 53, 69, 0.9) 0%,
rgba(220, 53, 69, 0.95) 50%,
rgba(220, 53, 69, 0.9) 100%);
color: white;
padding: 12px 0;
font-size: 18px;
font-weight: 500;
overflow: hidden;
white-space: nowrap;
opacity: 0;
animation: fadeIn 1s ease-in 1s forwards;
}
.ticker-text {
display: inline-block;
animation: scroll 30s linear infinite;
padding-left: 100%;
text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
}
.progress-bar {
position: absolute;
bottom: 0;
left: 0;
height: 4px;
background: linear-gradient(90deg, #007bff, #0056b3);
transition: width 0.3s ease;
opacity: 0.8;
}
.logo {
position: absolute;
top: 20px;
left: 20px;
width: 80px;
height: 80px;
opacity: 0;
animation: logoSlideIn 1.5s ease-out 1.5s forwards;
}
.logo img {
width: 100%;
height: 100%;
object-fit: contain;
} }
.corner-indicator { .stats-panel {
position: absolute; position: absolute;
top: 10px; top: 50%;
left: 10px; right: 20px;
background: blue; transform: translateY(-50%);
background: rgba(0, 0, 0, 0.7);
border-radius: 10px;
padding: 20px;
color: white; color: white;
padding: 10px;
font-size: 16px; font-size: 16px;
opacity: 0;
animation: slideInRight 1s ease-out 2.5s forwards;
min-width: 200px;
}
.stats-item {
margin-bottom: 10px;
display: flex;
justify-content: space-between;
}
.canvas-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 500;
}
/* Animations */
@keyframes titleSlideIn {
0% {
opacity: 0;
transform: translateX(-50%) translateY(-50px);
}
100% {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes scroll {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100%);
}
}
@keyframes logoSlideIn {
0% {
opacity: 0;
transform: translateX(-100px);
}
100% {
opacity: 0.9;
transform: translateX(0);
}
}
@keyframes slideInRight {
0% {
opacity: 0;
transform: translateY(-50%) translateX(100px);
}
100% {
opacity: 1;
transform: translateY(-50%) translateX(0);
}
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
}
/* Responsive Design */
@media (max-width: 1200px) {
.title-main {
font-size: 36px;
}
.title-subtitle {
font-size: 20px;
}
.news-ticker {
font-size: 16px;
}
}
@media (max-width: 800px) {
.title-main {
font-size: 28px;
}
.title-subtitle {
font-size: 16px;
}
.stats-panel {
right: 10px;
font-size: 14px;
padding: 15px;
}
} }
</style> </style>
</head> </head>
<body> <body>
<div class="corner-indicator"> <div class="overlay-container">
WebEngine Active <div class="logo" id="logo">
</div> <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iODAiIGhlaWdodD0iODAiIHZpZXdCb3g9IjAgMCA4MCA4MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjgwIiBoZWlnaHQ9IjgwIiByeD0iMTAiIGZpbGw9IiNkYzM1NDUiLz4KPHRleHQgeD0iNDAiIHk9IjQ1IiBmb250LWZhbWlseT0iQXJpYWwsIHNhbnMtc2VyaWYiIGZvbnQtc2l6ZT0iMjQiIGZvbnQtd2VpZ2h0PSJib2xkIiBmaWxsPSJ3aGl0ZSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zNWVtIj5NPC90ZXh0Pgo8L3N2Zz4K" alt="MbetterClient Logo" onerror="this.style.display='none'">
</div>
<div class="test-overlay">
OVERLAY TEST<br> <div class="title-main" id="titleMain">
This should be VISIBLE<br> MbetterClient Video Player
If you see this, WebEngine is working </div>
<div class="title-subtitle" id="titleSubtitle">
Ready for Content
</div>
<div class="news-ticker" id="newsTicker">
<div class="ticker-text" id="tickerText">
Welcome to MbetterClient • Professional Video Overlay System • Real-time Updates • Hardware Accelerated Playback
</div>
</div>
<div class="stats-panel" id="statsPanel" style="display: none;">
<div class="stats-item">
<span>Resolution:</span>
<span id="resolution">1920x1080</span>
</div>
<div class="stats-item">
<span>Bitrate:</span>
<span id="bitrate">5.2 Mbps</span>
</div>
<div class="stats-item">
<span>Codec:</span>
<span id="codec">H.264</span>
</div>
<div class="stats-item">
<span>FPS:</span>
<span id="fps">30.0</span>
</div>
</div>
<canvas class="canvas-overlay" id="canvasOverlay"></canvas>
<div class="progress-bar" id="progressBar" style="width: 0%;"></div>
</div> </div>
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script> <script>
console.log('=== WebEngine Overlay Test v4.0 ==='); class OverlayManager {
console.log('Document loaded'); constructor() {
console.log('Body background:', window.getComputedStyle(document.body).backgroundColor); this.channel = null;
this.overlayData = {};
// Simple test - change background after 2 seconds this.canvas = null;
setTimeout(() => { this.ctx = null;
document.body.style.background = 'rgba(0, 0, 255, 0.3)'; // Blue this.animationFrame = null;
console.log('Background changed to blue'); this.webChannelReady = false;
}, 2000); this.pendingUpdates = [];
// Wait for DOM to be fully loaded before accessing elements
this.waitForDOM(() => {
this.canvas = document.getElementById('canvasOverlay');
if (this.canvas) {
this.ctx = this.canvas.getContext('2d');
// Resize canvas to match window
this.resizeCanvas();
window.addEventListener('resize', () => this.resizeCanvas());
// Start canvas animations
this.startCanvasAnimations();
}
// Initialize WebChannel after DOM is ready
this.initWebChannel();
});
console.log('OverlayManager constructor called');
}
waitForDOM(callback) {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', callback);
} else {
callback();
}
}
resizeCanvas() {
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
}
initWebChannel() {
try {
if (typeof qt === 'undefined' || !qt.webChannelTransport) {
console.log('WebChannel transport not ready, retrying in 200ms...');
setTimeout(() => this.initWebChannel(), 200);
return;
}
new QWebChannel(qt.webChannelTransport, (channel) => {
// Validate channel and critical objects exist
if (!channel || !channel.objects) {
console.warn('Invalid WebChannel received, retrying...');
setTimeout(() => this.initWebChannel(), 300);
return;
}
this.channel = channel;
// Wait for both DOM and WebChannel to be fully ready
this.waitForFullInitialization(() => {
this.webChannelReady = true;
// Register for updates from Python with error handling
if (channel.objects.overlay) {
try {
channel.objects.overlay.dataUpdated.connect((data) => {
this.updateOverlay(data);
});
channel.objects.overlay.positionChanged.connect((position, duration) => {
this.updateProgress(position, duration);
});
channel.objects.overlay.videoInfoChanged.connect((info) => {
this.updateVideoInfo(info);
});
console.log('WebChannel connected and ready');
// Process any pending updates after full initialization
setTimeout(() => this.processPendingUpdates(), 100);
} catch (connectError) {
console.error('Error connecting WebChannel signals:', connectError);
}
} else {
console.warn('WebChannel overlay object not found');
}
});
});
} catch (error) {
console.error('WebChannel initialization error:', error);
// Retry with exponential backoff
setTimeout(() => this.initWebChannel(), 1000);
}
}
waitForFullInitialization(callback) {
const checkReady = () => {
if (document.readyState === 'complete' && this.validateCriticalElements()) {
callback();
} else {
setTimeout(checkReady, 100);
}
};
checkReady();
}
processPendingUpdates() {
// Prevent infinite loops by limiting processing attempts
let processed = 0;
const maxProcessing = 10;
while (this.pendingUpdates.length > 0 && processed < maxProcessing) {
// Double-check readiness before processing
if (!this.isSystemReady()) {
console.log('System not ready during pending updates processing');
break;
}
const update = this.pendingUpdates.shift();
this.updateOverlay(update);
processed++;
}
// If there are still pending updates, schedule another processing cycle
if (this.pendingUpdates.length > 0) {
setTimeout(() => this.processPendingUpdates(), 300);
}
}
updateOverlay(data) {
console.log('Updating overlay with data:', data);
// Enhanced readiness check with multiple validation layers
if (!this.isSystemReady()) {
console.log('System not ready, queuing update');
this.pendingUpdates.push(data);
// Retry with progressive backoff
setTimeout(() => this.processPendingUpdates(), 150);
return;
}
// Validate all critical elements exist before any updates
if (!this.validateCriticalElements()) {
console.warn('Critical elements not available, requeueing update');
this.pendingUpdates.push(data);
setTimeout(() => this.processPendingUpdates(), 200);
return;
}
this.overlayData = { ...this.overlayData, ...data };
// Update title elements with safe element access
if (data.title !== undefined) {
if (!this.safeUpdateElement('titleMain', data.title, 'textContent')) {
console.warn('Failed to update titleMain, queuing for retry');
this.pendingUpdates.push({title: data.title});
return;
}
}
if (data.subtitle !== undefined) {
if (!this.safeUpdateElement('titleSubtitle', data.subtitle, 'textContent')) {
console.warn('Failed to update titleSubtitle, queuing for retry');
this.pendingUpdates.push({subtitle: data.subtitle});
return;
}
}
// Update ticker text
if (data.ticker !== undefined) {
if (!this.safeUpdateElement('tickerText', data.ticker, 'textContent')) {
console.warn('Failed to update tickerText, queuing for retry');
this.pendingUpdates.push({ticker: data.ticker});
return;
}
}
// Show/hide stats panel
if (data.showStats !== undefined) {
if (!this.safeUpdateElement('statsPanel', data.showStats ? 'block' : 'none', 'display')) {
console.warn('Failed to update statsPanel, queuing for retry');
this.pendingUpdates.push({showStats: data.showStats});
return;
}
}
// Update custom CSS if provided
if (data.customCSS) {
this.applyCustomCSS(data.customCSS);
}
}
isSystemReady() {
try {
return this.webChannelReady &&
document.readyState === 'complete' &&
document.getElementById('titleMain') !== null &&
document.body !== null;
} catch (error) {
console.warn('Error in isSystemReady check:', error);
return false;
}
}
validateCriticalElements() {
try {
const criticalIds = ['titleMain', 'titleSubtitle', 'tickerText', 'statsPanel', 'progressBar'];
for (const id of criticalIds) {
const element = document.getElementById(id);
if (!element) {
console.warn(`Critical element ${id} not found`);
return false;
}
// Additional check for element validity
if (element.parentNode === null || !document.contains(element)) {
console.warn(`Critical element ${id} not properly attached to DOM`);
return false;
}
}
return true;
} catch (error) {
console.warn('Error in validateCriticalElements:', error);
return false;
}
}
safeUpdateElement(elementId, value, property = 'textContent') {
try {
const element = document.getElementById(elementId);
if (!element) {
console.warn(`Element ${elementId} not found`);
return false;
}
// Double-check element is still valid and in DOM
if (element.parentNode === null) {
console.warn(`Element ${elementId} no longer in DOM`);
return false;
}
// Additional check for element accessibility
if (!document.contains(element)) {
console.warn(`Element ${elementId} not contained in document`);
return false;
}
if (property === 'display') {
element.style.display = value;
} else if (property === 'width') {
element.style.width = value;
} else if (property === 'textContent') {
// Check if textContent property exists and is writable
if ('textContent' in element) {
element.textContent = value || '';
// Animate only if element update succeeded
this.animateElement(elementId, 'pulse');
} else {
console.warn(`Element ${elementId} does not support textContent`);
return false;
}
}
return true;
} catch (error) {
console.error(`Error updating element ${elementId}:`, error);
return false;
}
}
updateProgress(position, duration) {
try {
// Check system readiness before updating progress
if (!this.isSystemReady()) {
console.log('System not ready for progress update, skipping');
return;
}
const percentage = duration > 0 ? (position / duration) * 100 : 0;
// Safe progress bar update
this.safeUpdateElement('progressBar', `${percentage}%`, 'width');
} catch (error) {
console.error('Error updating progress:', error);
}
}
updateVideoInfo(info) {
console.log('Video info updated:', info);
if (info.resolution) {
const resolutionElement = document.getElementById('resolution');
if (resolutionElement) {
resolutionElement.textContent = info.resolution;
}
}
if (info.bitrate) {
const bitrateElement = document.getElementById('bitrate');
if (bitrateElement) {
bitrateElement.textContent = info.bitrate;
}
}
if (info.codec) {
const codecElement = document.getElementById('codec');
if (codecElement) {
codecElement.textContent = info.codec;
}
}
if (info.fps) {
const fpsElement = document.getElementById('fps');
if (fpsElement) {
fpsElement.textContent = info.fps;
}
}
}
formatTime(seconds) {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
}
animateElement(elementId, animationClass) {
const element = document.getElementById(elementId);
if (element) {
element.style.animation = 'none';
element.offsetHeight; // Trigger reflow
element.style.animation = `${animationClass} 1s ease-in-out`;
}
}
applyCustomCSS(css) {
let styleElement = document.getElementById('customStyles');
if (!styleElement) {
styleElement = document.createElement('style');
styleElement.id = 'customStyles';
document.head.appendChild(styleElement);
}
styleElement.textContent = css;
}
startCanvasAnimations() {
if (!this.canvas || !this.ctx) {
console.warn('Canvas not ready for animations');
return;
}
const animate = () => {
if (this.ctx && this.canvas) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Draw animated particles or custom graphics
this.drawParticles();
this.animationFrame = requestAnimationFrame(animate);
}
};
animate();
}
drawParticles() {
// Example particle system - can be customized
const time = Date.now() * 0.001;
for (let i = 0; i < 5; i++) {
const x = (Math.sin(time + i) * 100) + this.canvas.width / 2;
const y = (Math.cos(time + i * 0.5) * 50) + this.canvas.height / 2;
this.ctx.beginPath();
this.ctx.arc(x, y, 2, 0, Math.PI * 2);
this.ctx.fillStyle = `rgba(255, 255, 255, ${0.1 + Math.sin(time + i) * 0.1})`;
this.ctx.fill();
}
}
// Public API for Python to call
setTitle(title) {
this.updateOverlay({ title });
}
setSubtitle(subtitle) {
this.updateOverlay({ subtitle });
}
setTicker(ticker) {
this.updateOverlay({ ticker });
}
showStats(show) {
this.updateOverlay({ showStats: show });
}
cleanup() {
if (this.animationFrame) {
cancelAnimationFrame(this.animationFrame);
}
}
}
// Initialize overlay manager immediately and safely
let overlayManager = null;
// Function to ensure DOM is ready before any operations
function ensureOverlayReady(callback) {
if (overlayManager && overlayManager.webChannelReady) {
callback();
} else {
setTimeout(() => ensureOverlayReady(callback), 50);
}
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => {
overlayManager = new OverlayManager();
window.overlayManager = overlayManager;
});
} else {
// DOM already loaded
overlayManager = new OverlayManager();
window.overlayManager = overlayManager;
}
// Cleanup on unload
window.addEventListener('beforeunload', () => {
if (overlayManager) {
overlayManager.cleanup();
}
});
// Safe global functions that wait for overlay to be ready
window.safeUpdateOverlay = function(data) {
ensureOverlayReady(() => {
if (overlayManager) {
overlayManager.updateOverlay(data);
}
});
};
window.safeUpdateProgress = function(position, duration) {
ensureOverlayReady(() => {
if (overlayManager) {
overlayManager.updateProgress(position, duration);
}
});
};
</script> </script>
</body> </body>
</html> </html>
\ 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