Loading stream...
-

{
streamImg.src = streamImg.src + '?retry=' + Date.now();
}, 2000);
@@ -763,11 +764,10 @@
});
function goBack() {
- // Check if user came from mobile by looking at referrer or user agent
- const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
+ // Check if user came specifically from a mobile page by looking at referrer
const referrer = document.referrer;
- if (isMobile || referrer.includes('/mobile/')) {
+ if (referrer.includes('/mobile/')) {
window.location.href = '/mobile/streams';
} else {
window.location.href = '/';
diff --git a/templates/index.html b/templates/index.html
index 849e065..4b23698 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -152,21 +152,26 @@
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(2, 1fr);
- gap: 20px;
- padding: 20px;
+ gap: 15px;
+ padding: 15px;
box-sizing: border-box;
+ align-items: stretch;
+ justify-items: stretch;
}
.camera-card {
- background: #2a2a2a;
+ background: transparent;
border-radius: 12px;
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
overflow: hidden;
display: flex;
flex-direction: column;
+ align-items: center;
+ justify-content: center;
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
position: relative;
+ width: 100%;
+ height: 100%;
}
.camera-card:hover {
@@ -189,22 +194,55 @@
.stream-wrapper {
position: relative;
- width: 100%;
- flex: 1;
- background: #222;
+ background: #2a2a2a;
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
overflow: hidden;
pointer-events: none;
+ display: flex;
+ flex-direction: column;
+ max-width: 100%;
+ max-height: 100%;
+ }
+
+ .image-container {
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex: 1;
+ }
+
+ .stream-placeholder {
+ width: 640px;
+ height: 480px;
+ max-width: 100%;
+ max-height: 100%;
+ display: block;
+ z-index: 5;
+ }
+
+ .stream-placeholder svg {
+ width: 100%;
+ height: 100%;
+ display: block;
}
.stream {
+ position: absolute;
+ top: 0;
+ left: 0;
width: 100%;
height: 100%;
- object-fit: cover;
+ object-fit: contain;
+ object-position: center;
display: block;
transition: opacity 0.3s ease;
pointer-events: none;
+ z-index: 10;
}
+
/* Camera Number Indicator */
.card-header {
background: linear-gradient(90deg, #007bff 0%, #007bff 60px, #1a1a1a 60px);
@@ -214,7 +252,8 @@
align-items: center;
gap: 0;
transition: all 0.2s ease;
- position: relative;
+ border-radius: 12px 12px 0 0;
+ flex-shrink: 0;
}
.target-number {
@@ -711,12 +750,29 @@
{% for i in range(1, 7) %}
-
-

+
+
+
+
+
+

+
{% endfor %}
@@ -1040,14 +1096,32 @@
const debouncedSaveSettings = debounce(saveSettings, 500);
- // Mobile device detection
- function isMobileDevice() {
- return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ||
- (window.innerWidth <= 1024 && window.innerHeight <= 1366) ||
- ('ontouchstart' in window) ||
- (navigator.maxTouchPoints > 0);
+ // Handle stream loading success
+ function handleStreamLoad(img, cameraId) {
+ console.log(`✅ Camera ${cameraId} loaded successfully`);
+ img.style.opacity = '1';
+
+ // Hide placeholder when stream loads
+ const placeholder = document.getElementById(`placeholder${cameraId}`);
+ if (placeholder) {
+ placeholder.style.display = 'none';
+ }
}
+ // Handle stream loading error
+ function handleStreamError(img, cameraId) {
+ console.log(`❌ Camera ${cameraId} failed to load - showing placeholder`);
+ img.style.display = 'none';
+
+ // Show placeholder when stream fails
+ const placeholder = document.getElementById(`placeholder${cameraId}`);
+ if (placeholder) {
+ placeholder.style.display = 'flex';
+ }
+ }
+
+
+
// Update card title
function updateCardTitle(index) {
if (tournamentActive) return;
@@ -1255,7 +1329,7 @@
// Add touch feedback for interactive elements on touch devices
function addTouchFeedback() {
- if (isMobileDevice()) {
+ if ('ontouchstart' in window) {
const touchElements = document.querySelectorAll('.camera-card, .nav-btn, .hamburger-menu');
touchElements.forEach(element => {
@@ -1317,16 +1391,17 @@