Update index.html

many optimizings
This commit is contained in:
2024-08-11 11:40:12 +02:00
committed by GitHub
parent c453ea331c
commit dedf708c3b
+155 -373
View File
@@ -2,25 +2,25 @@
session_start(); session_start();
error_reporting(E_ALL); error_reporting(E_ALL);
ini_set('display_errors', 1); ini_set('display_errors', 1);
$imageDir = "./image"; // Angepasst an das Ausgabeverzeichnis des Bash-Skripts $imageDir = "./image"; // Angepasst an das Ausgabeverzeichnis des Bash-Skripts
$imageFiles = glob("$imageDir/screenshot_*.jpg"); $imageFiles = glob("$imageDir/screenshot_*.jpg");
rsort($imageFiles); // Sortiert die Dateien in umgekehrter Reihenfolge (neueste zuerst) rsort($imageFiles); // Sortiert die Dateien in umgekehrter Reihenfolge (neueste zuerst)
$imageFilesJson = json_encode($imageFiles); $imageFilesJson = json_encode($imageFiles);
class WebcamManager { class WebcamManager {
private $videoSrc = 'test_video.m3u8'; private $videoSrc = 'test_video.m3u8';
private $logoPath = 'logo.png'; private $logoPath = 'logo.png';
public function displayWebcam() { public function displayWebcam() {
return '<video id="webcam-player" controls autoplay muted></video>'; return '<video id="webcam-player" controls autoplay muted></video>';
} }
public function captureSnapshot() { public function captureSnapshot() {
$outputFile = 'snapshot_' . date('YmdHis') . '.jpg'; $outputFile = 'snapshot_' . date('YmdHis') . '.jpg';
$command = "ffmpeg -i {$this->videoSrc} -i {$this->logoPath} -filter_complex 'overlay=10:10' -vframes 1 -q:v 2 {$outputFile}"; $command = "ffmpeg -i {$this->videoSrc} -i {$this->logoPath} -filter_complex 'overlay=10:10' -vframes 1 -q:v 2 {$outputFile}";
@@ -30,6 +30,22 @@ class WebcamManager {
return "Fehler beim Erstellen des Snapshots."; return "Fehler beim Erstellen des Snapshots.";
} }
// Kopieren des Snapshots in den Uploads-Ordner
$uploadDir = "uploads/";
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
}
$uploadFile = $uploadDir . $outputFile;
if (copy($outputFile, $uploadFile)) {
} else {
}
header('Content-Type: application/octet-stream'); header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . $outputFile . '"'); header('Content-Disposition: attachment; filename="' . $outputFile . '"');
readfile($outputFile); readfile($outputFile);
@@ -51,6 +67,22 @@ class WebcamManager {
return "Fehler beim Erstellen der Video-Sequenz."; return "Fehler beim Erstellen der Video-Sequenz.";
} }
// Kopieren des Videoclips in den Uploads-Ordner
$uploadDir = "uploads/";
if (!file_exists($uploadDir)) {
mkdir($uploadDir, 0777, true);
echo "Uploads-Ordner erstellt.<br>";
}
$uploadFile = $uploadDir . $outputFile;
if (copy($outputFile, $uploadFile)) {
} else {
echo "Fehler beim Kopieren des Videoclips in den Uploads-Ordner.<br>";
}
header('Content-Type: video/mp4'); header('Content-Type: video/mp4');
header('Content-Disposition: attachment; filename="' . $outputFile . '"'); header('Content-Disposition: attachment; filename="' . $outputFile . '"');
readfile($outputFile); readfile($outputFile);
@@ -58,15 +90,6 @@ class WebcamManager {
exit; exit;
} }
public function getJavaScript() { public function getJavaScript() {
return " return "
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
@@ -317,26 +340,6 @@ class AdminManager {
$output .= '</div>'; $output .= '</div>';
return $output; return $output;
} }
public function handleSocialMediaUpdate($platform, $url) { public function handleSocialMediaUpdate($platform, $url) {
$socialLinks = json_decode(file_get_contents('social_links.json') ?: '{}', true); $socialLinks = json_decode(file_get_contents('social_links.json') ?: '{}', true);
$socialLinks[$platform] = $url; $socialLinks[$platform] = $url;
@@ -354,12 +357,18 @@ if (isset($_GET['action'])) {
switch ($_GET['action']) { switch ($_GET['action']) {
case 'snapshot': case 'snapshot':
$webcamManager->captureSnapshot(); $webcamManager->captureSnapshot();
break; break;
case 'sequence': case 'sequence':
$webcamManager->captureVideoSequence(); $webcamManager->captureVideoSequence();
break; break;
} }
} }
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_guestbook') { if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'delete_guestbook') {
if ($adminManager->isAdmin() && isset($_POST['delete_entry'])) { if ($adminManager->isAdmin() && isset($_POST['delete_entry'])) {
$index = $_POST['delete_entry']; $index = $_POST['delete_entry'];
@@ -457,25 +466,31 @@ header {
.button:hover { .button:hover {
background-color: #45a049; background-color: #45a049;
} }
#webcam-player { #webcam-player {
max-width: 100%; max-width: 100%;
height: auto; height: auto;
max-height: 70vh; /* Begrenzt die Höhe auf 70% der Bildschirmhöhe */ max-height: 70vh; /* Begrenzt die Höhe auf 70% der Bildschirmhöhe */
display: block; display: block;
margin: 702px auto 0; /* Fügt einen oberen Abstand von 20px hinzu */ margin: 0 auto;
} }
.video-container { .video-container {
margin-top: 20px; /* Fügt einen oberen Abstand von 20px hinzu */ position: relative;
padding-bottom: 56.25%; /* 16:9 Seitenverhältnis */
height: 0;
overflow: hidden;
} }
.video-container #webcam-player { .video-container #webcam-player {
position: absolute;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.delete-btn { .delete-btn {
background-color: #ff4136; background-color: #ff4136;
color: white; color: white;
@@ -496,8 +511,8 @@ header {
background-size: cover; background-size: cover;
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
padding: 50px 0; padding: 50px 0; /* Anpassen der Polsterung nach Bedarf */
color: #fff; color: #fff; /* Textfarbe anpassen, um Lesbarkeit auf dem Hintergrund zu gewährleisten */
} }
@@ -961,7 +976,7 @@ footer {
background-color: #45a049; background-color: #45a049;
} }
.main-content { .main-content {
position: 2px; position: relative;
min-height: 100vh; min-height: 100vh;
} }
@@ -999,234 +1014,8 @@ footer {
</style> </style>
</style> </style>
<script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"></script>
</head> </head>
<body> <body>
<header> <header>
@@ -1250,54 +1039,50 @@ footer {
</nav> </nav>
</div> </div>
</header> </header>
<div class="main-content"> <div class="main-content">
<section class="title-section"> <section class="title-section">
<div class="container"> <div class="container">
<div id="welcome-title">Willkommen bei Aurora Wetter Lifecam</div> <div id="welcome-title">Willkommen bei Aurora Wetter Lifecam</div>
<div id="welcome-subtitle">Erleben Sie faszinierende Ausblicke der Zürcher Region - in Echtzeit!</div> <div id="welcome-subtitle">Erleben Sie faszinierende Ausblicke der Züricher Region - in Echtzeit!</div>
</div> </div>
</section> </section>
<div class="banner-container"> <div class="banner-container">
<div class="recommendation-banner"> <div class="recommendation-banner">
<h2>Unsere Empfehlungen</h2> <h2>Unsere Empfehlungen</h2>
<div class="sponsor-logos"> <div class="sponsor-logos">
<?php <?php
$advertisements = [ $advertisements = [
['name' => 'Gartencenter Meier', 'url' => 'https://www.gartencenter-meier.ch', 'img' => 'meier.png', 'text' => 'Gartencenter Meier'], ['name' => 'Gartencenter Meier', 'url' => 'https://www.gartencenter-meier.ch', 'img' => 'meier.png'],
['name' => 'Restaurant Schweizerhof', 'url' => 'https://schweizerhof-duernten.ch/', 'img' => 'schweiz.png', 'text' => 'Hotel Schweizerhof'], ['name' => 'Restaurant Schweizerhof', 'url' => 'https://schweizerhof-duernten.ch/', 'img' => 'schweiz.png'],
['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png', 'text' => 'Werben Sie hier'], ['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png'],
['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png'],
['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png', 'text' => 'Werben Sie hier'], ['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png'],
['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png', 'text' => 'Werben Sie hier'], ['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png'],
['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png', 'text' => 'Werben Sie hier'], ['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png'],
['name' => 'Deine Werbung bei uns', 'url' => 'https://www.aurora-wetter-lifecam.ch/', 'img' => 'werbung.png']
// Fügen Sie hier weitere Werbeanzeigen hinzu
]; ];
$grouped_ads = array_chunk($advertisements, 3); $grouped_ads = array_chunk($advertisements, 5);
foreach ($grouped_ads as $group) { foreach ($grouped_ads as $group) {
echo '<div class="ad-row">'; echo '<div class="ad-row">';
foreach ($group as $ad) { foreach ($group as $ad) {
echo '<div class="ad-item"> echo '<div class="ad-item">
<a href="' . htmlspecialchars($ad['url']) . '" target="_blank"> <a href="' . $ad['url'] . '" target="_blank">
<img src="' . htmlspecialchars($ad['img']) . '" alt="' . htmlspecialchars($ad['name']) . '"> <img src="' . $ad['img'] . '" alt="' . $ad['name'] . '">
<p>' . htmlspecialchars($ad['text']) . '</p>
</a> </a>
</div>';
}
</div>'; echo '</div>';
} }
?>
echo '</div>'; </div>
}
?>
</div> </div>
</div> </div>
</div> </div>
@@ -1306,19 +1091,13 @@ footer {
<section id="webcams" class="section"> <section id="webcams" class="section">
<div class="container"> <div class="container">
<div class="video-container"> <div class="video-container">
<?php echo $webcamManager->displayWebcam(); ?> <?php echo $webcamManager->displayWebcam(); ?>
<div id="timelapse-viewer" class="video-container" style=" margin-top: 300px; max-width: 100%; <div id="timelapse-viewer" style="display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%;">
height: auto; <img id="timelapse-image" src="" alt="Timelapse Image" style="width: 100%; height: 100%; object-fit: cover;">
max-height: 70vh;">
<img id="timelapse-image" src="" alt="Timelapse Image" class="video-container" style=" margin-top: 500px; max-width: 100%;
height: auto;
max-height: 70vh;">>
</div> </div>
@@ -1397,11 +1176,6 @@ footer {
</div> </div>
</div> </div>
</section> </section>
<section id="ueber-uns" class="section"> <section id="ueber-uns" class="section">
<div class="container"> <div class="container">
<h2>Über unser Projekt</h2> <h2>Über unser Projekt</h2>
@@ -1413,18 +1187,6 @@ footer {
</div> </div>
</div> </div>
</section> </section>
<?php if ($adminManager->isAdmin()): ?> <?php if ($adminManager->isAdmin()): ?>
<section id="admin" class="section"> <section id="admin" class="section">
<div class="container"> <div class="container">
@@ -1458,6 +1220,8 @@ footer {
<a href="#guestbook">Gästebuch</a> <a href="#guestbook">Gästebuch</a>
<a href="#kontakt">Kontakt</a> <a href="#kontakt">Kontakt</a>
<a href="#gallery">Galerie</a> <a href="#gallery">Galerie</a>
<a href="#impressum">Impressum</a>
</div> </div>
<div class="footer-bottom"> <div class="footer-bottom">
<p>&copy; 2024 Aurora Wetter Lifecam</p> <p>&copy; 2024 Aurora Wetter Lifecam</p>
@@ -1577,14 +1341,6 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
</script> </script>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var timelapseButton = document.getElementById('timelapse-button'); var timelapseButton = document.getElementById('timelapse-button');
@@ -1624,44 +1380,74 @@ document.addEventListener('DOMContentLoaded', function() {
sunnyTimelapseButton.textContent = 'Nur sonnige Bilder zeigen'; sunnyTimelapseButton.textContent = 'Nur sonnige Bilder zeigen';
} }
} }
const imageCache = new Map();
const imageCache = new Map();
const preloadBuffer = 5; // Anzahl der im Voraus zu ladenden Bilder const preloadBuffer = 5; // Anzahl der im Voraus zu ladenden Bilder
async function startTimelapse() { async function startTimelapse() {
console.log("startTimelapse wurde aufgerufen");
if (imageFiles.length === 0) { if (imageFiles.length === 0) {
console.log("Keine Bilder gefunden"); console.log("Keine Bilder gefunden");
return; return;
} }
timelapseInterval = setInterval(async function() { const displayDuration = 20.83; // Millisekunden pro Bild
console.log(`Anzeigedauer pro Bild: ${displayDuration} ms`);
async function showNextImage() {
console.log(`Aktueller Bildindex: ${currentImageIndex}`);
while (currentImageIndex < imageFiles.length) { while (currentImageIndex < imageFiles.length) {
const currentImage = imageFiles[currentImageIndex]; const currentImage = imageFiles[currentImageIndex];
console.log(`Verarbeite Bild: ${currentImage}`);
// Lazy Loading: Lade das aktuelle Bild und die nächsten paar // Lazy Loading
for (let i = currentImageIndex; i < currentImageIndex + preloadBuffer && i < imageFiles.length; i++) { for (let i = currentImageIndex; i < currentImageIndex + preloadBuffer && i < imageFiles.length; i++) {
if (!imageCache.has(imageFiles[i])) { if (!imageCache.has(imageFiles[i])) {
console.log(`Lade Bild in Cache: ${imageFiles[i]}`);
imageCache.set(imageFiles[i], getImageData(imageFiles[i])); imageCache.set(imageFiles[i], getImageData(imageFiles[i]));
} }
} }
const imageData = await imageCache.get(currentImage); try {
if (!isGreyImage(imageData) && (!showOnlySunny || isSunnyImage(imageData))) { const imageData = await imageCache.get(currentImage);
timelapseImage.src = currentImage; if (!isGreyImage(imageData) && (!showOnlySunny || isSunnyImage(imageData))) {
currentImageIndex++; console.log(`Zeige Bild an: ${currentImage}`);
timelapseImage.src = currentImage;
// Cache-Bereinigung: Entferne alte Bilder aus dem Cache currentImageIndex++;
if (imageCache.size > preloadBuffer * 2) {
const keysToDelete = Array.from(imageCache.keys()).slice(0, imageCache.size - preloadBuffer); // Cache-Bereinigung
keysToDelete.forEach(key => imageCache.delete(key)); if (imageCache.size > preloadBuffer * 2) {
console.log("Führe Cache-Bereinigung durch");
const keysToDelete = Array.from(imageCache.keys()).slice(0, imageCache.size - preloadBuffer);
keysToDelete.forEach(key => imageCache.delete(key));
}
await new Promise(resolve => setTimeout(resolve, displayDuration));
return;
} else {
console.log(`Überspringe Bild: ${currentImage}`);
} }
} catch (error) {
return; console.error(`Fehler beim Verarbeiten des Bildes ${currentImage}:`, error);
} }
currentImageIndex++; currentImageIndex++;
} }
currentImageIndex = 0; // Zurück zum Anfang, wenn alle Bilder durchlaufen wurden console.log("Alle Bilder durchlaufen, setze Index zurück");
}, 500); currentImageIndex = 0;
}
async function runTimelapse() {
console.log("runTimelapse gestartet");
while (timelapseViewer.style.display !== 'none') {
await showNextImage();
}
console.log("Zeitraffer beendet");
}
runTimelapse().catch(error => console.error("Fehler im Zeitraffer:", error));
} }
function updateTimelapseImage() { function updateTimelapseImage() {
timelapseImage.src = imageFiles[currentImageIndex]; timelapseImage.src = imageFiles[currentImageIndex];
timelapseSlider.value = currentImageIndex; timelapseSlider.value = currentImageIndex;
@@ -1697,7 +1483,6 @@ function getImageData(src) {
} }
function stopTimelapse() { function stopTimelapse() {
clearInterval(timelapseInterval); clearInterval(timelapseInterval);
currentImageIndex = 0; currentImageIndex = 0;
@@ -1721,12 +1506,12 @@ function getImageData(src) {
} }
return true; // Das Bild ist grau, aber natürlich :) return true; // Das Bild ist grau, aber natürlich :)
} }
function isSunnyImage(imageData) { function isSunnyImage(imageData) {
const data = imageData.data; const data = imageData.data;
const width = imageData.width; const width = imageData.width;
const height = imageData.height; const height = imageData.height;
// Nur den oberen Drittel des Bildes analysieren // Nur den oberen Drittel des Bildes analysieren
const searchHeight = Math.floor(height / 3); const searchHeight = Math.floor(height / 3);
@@ -1759,21 +1544,8 @@ function isSunnyImage(imageData) {
// Als sonnig betrachten, wenn genügend gelbe Pixel gefunden wurden // Als sonnig betrachten, wenn genügend gelbe Pixel gefunden wurden
return sunPixels > minSunSize * minSunSize; return sunPixels > minSunSize * minSunSize;
} }
}); });
</script> </script>
<script> <script>
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
var qrCodeElement = document.getElementById('qrcode'); var qrCodeElement = document.getElementById('qrcode');
@@ -1787,9 +1559,6 @@ document.addEventListener('DOMContentLoaded', function() {
}); });
}); });
</script> </script>
<div id="imageModal" class="modal"> <div id="imageModal" class="modal">
<span class="close">&times;</span> <span class="close">&times;</span>
<img class="modal-content" id="modalImage"> <img class="modal-content" id="modalImage">
@@ -1798,6 +1567,19 @@ document.addEventListener('DOMContentLoaded', function() {
</div> </div>
<section id="impressum" class="section">
<div class="container">
<h2>Impressum</h2>
<p>Aurora Wetter Lifecam</p>
<p>Musterstraße 123</p>
<p>12345 Musterstadt</p>
<p>Schweiz</p>
<p>E-Mail: info@aurora-wetter-lifecam.ch</p>
<p>Telefon: +41 123 456 789</p>
<p>Verantwortlich für den Inhalt: Max Mustermann</p>
</div>
</section>
</body> </body>