diff --git a/aurora-livecam/index.php b/aurora-livecam/index.php
index 567eba6..d3a45e1 100644
--- a/aurora-livecam/index.php
+++ b/aurora-livecam/index.php
@@ -8,216 +8,113 @@ require_once 'SettingsManager.php';
// SettingsManager initialisieren
$settingsManager = new SettingsManager();
-// AJAX-Handler für Settings (VOR anderen Ausgaben!)
-$settingsManager->handleAjax();
+// AJAX-Handler für Settings (MUSS ganz am Anfang sein!)
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['settings_action'])) {
+ header('Content-Type: application/json');
+
+ switch ($_POST['settings_action']) {
+ case 'get':
+ echo json_encode(['success' => true, 'settings' => $settingsManager->get()]);
+ exit;
+
+ case 'update':
+ $key = $_POST['key'] ?? null;
+ $value = $_POST['value'] ?? null;
+
+ if ($value === 'true') $value = true;
+ if ($value === 'false') $value = false;
+ if (is_numeric($value)) $value = intval($value);
+
+ if ($key && $settingsManager->set($key, $value)) {
+ echo json_encode(['success' => true, 'message' => 'Gespeichert']);
+ } else {
+ echo json_encode(['success' => false, 'message' => 'Fehler']);
+ }
+ exit;
+ }
+}
if (isset($_GET['download_video'])) {
$videoDir = './videos/';
$latestVideo = null;
$latestTime = 0;
-
- // Finde das neueste Video
foreach (glob($videoDir . '*.mp4') as $video) {
$mtime = filemtime($video);
- if ($mtime > $latestTime) {
- $latestTime = $mtime;
- $latestVideo = $video;
- }
+ if ($mtime > $latestTime) { $latestTime = $mtime; $latestVideo = $video; }
}
-
if ($latestVideo) {
- header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.basename($latestVideo).'"');
- header('Expires: 0');
- header('Cache-Control: must-revalidate');
- header('Pragma: public');
header('Content-Length: ' . filesize($latestVideo));
readfile($latestVideo);
exit;
- } else {
- echo "Kein Video zum Herunterladen gefunden.";
- exit;
}
+ echo "Kein Video gefunden.";
+ exit;
}
-
-
-
-// Funktion zur sicheren Umleitung
-function safeRedirect($url) {
- if (!headers_sent()) {
- header("HTTP/1.1 301 Moved Permanently");
- header("Location: " . $url);
- } else {
- echo '';
- }
- exit();
-}
-
-// Hauptlogik
-$oldDomains = [
- 'www.aurora-wetter-lifecam.ch',
- 'www.aurora-wetter-livecam.ch'
-];
+$oldDomains = ['www.aurora-wetter-lifecam.ch', 'www.aurora-wetter-livecam.ch'];
$newDomain = 'www.aurora-weather-livecam.com';
-
-if (in_array($_SERVER['HTTP_HOST'], $oldDomains)) {
+if (in_array($_SERVER['HTTP_HOST'] ?? '', $oldDomains)) {
$protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
- $newUrl = $protocol . '://' . $newDomain . $_SERVER['REQUEST_URI'];
-
- // Logging für Debugging
- error_log("Umleitung von {$_SERVER['HTTP_HOST']} nach $newUrl");
-
- if (!headers_sent()) {
- header("HTTP/1.1 301 Moved Permanently");
- header("Location: " . $newUrl);
- } else {
- echo '';
- }
- exit();
+ header("HTTP/1.1 301 Moved Permanently");
+ header("Location: " . $protocol . '://' . $newDomain . $_SERVER['REQUEST_URI']);
+ exit;
}
-
-
-
-
session_start();
error_reporting(E_ALL);
-ini_set('display_errors', 1);
-$imageDir = "./image"; // Angepasst an das Ausgabeverzeichnis des Bash-Skripts
-$imageFiles = glob("$imageDir/screenshot_*.jpg");
-rsort($imageFiles); // Sortiert die Dateien in umgekehrter Reihenfolge (neueste zuerst)
-$imageFilesJson = json_encode($imageFiles);
+ini_set('display_errors', 0);
+$imageDir = "./image";
+$imageFiles = glob("$imageDir/screenshot_*.jpg");
+if ($imageFiles) rsort($imageFiles);
+$imageFilesJson = json_encode($imageFiles ?: []);
class ViewerCounter {
private $file = 'active_viewers.json';
- private $timeout = 30; // Zeit in Sekunden, bis ein User als "offline" gilt
+ private $timeout = 30;
public function handleHeartbeat() {
- $ip = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']); // Anonymisierte ID
+ $ip = md5($_SERVER['REMOTE_ADDR'] . ($_SERVER['HTTP_USER_AGENT'] ?? ''));
$now = time();
-
- $viewers = [];
-
- // 1. Datei lesen (mit Lock für Sicherheit bei vielen Zugriffen)
- if (file_exists($this->file)) {
- $content = file_get_contents($this->file);
- $viewers = json_decode($content, true) ?? [];
- }
-
- // 2. Aktuellen User updaten
+ $viewers = file_exists($this->file) ? json_decode(file_get_contents($this->file), true) ?? [] : [];
$viewers[$ip] = $now;
-
- // 3. Alte User entfernen & Zählen
- $activeCount = 0;
- $newViewers = [];
-
- foreach ($viewers as $userIp => $lastSeen) {
- if ($now - $lastSeen < $this->timeout) {
- $newViewers[$userIp] = $lastSeen;
- $activeCount++;
- }
- }
-
- // 4. Speichern
- file_put_contents($this->file, json_encode($newViewers));
-
- // 5. Ergebnis zurückgeben
+ $active = [];
+ foreach ($viewers as $u => $t) { if ($now - $t < $this->timeout) $active[$u] = $t; }
+ file_put_contents($this->file, json_encode($active));
header('Content-Type: application/json');
- echo json_encode(['count' => $activeCount]);
+ echo json_encode(['count' => count($active)]);
exit;
}
public function getInitialCount() {
if (file_exists($this->file)) {
- $viewers = json_decode(file_get_contents($this->file), true) ?? [];
- // Nur grob zählen, genaues Update macht das JS sofort nach Laden
- return count($viewers);
+ return max(1, count(json_decode(file_get_contents($this->file), true) ?? []));
}
- return 1; // Zumindest man selbst ist da
+ return 1;
}
}
-// Instanz erstellen
$viewerCounter = new ViewerCounter();
-
-
class WebcamManager {
private $videoSrc = 'test_video.m3u8';
- private $logoPath = 'logo.png';
- // Zeigt NUR das Video ohne Schnickschnack
public function displayWebcam() {
- return '
-
- ';
+ return ' ';
}
- // Das ist die neue Anzeige für unten links
public function displayStreamStats() {
- return '
-
-
-
Stream: 0.00 MBit/s
+ return '
+ 0.00 MBit/s
';
}
- public function captureSnapshot() {
- $outputFile = 'snapshot_' . date('YmdHis') . '.jpg';
- $src = escapeshellarg($this->videoSrc);
- $logo = escapeshellarg($this->logoPath);
- $command = "ffmpeg -i {$src} -i {$logo} -filter_complex 'overlay=main_w-overlay_w-10:10' -vframes 1 -q:v 2 {$outputFile}";
- exec($command, $output, $returnVar);
- if ($returnVar !== 0) return "Fehler";
-
- $uploadDir = "uploads/";
- if (!file_exists($uploadDir)) mkdir($uploadDir, 0777, true);
- $uploadFile = $uploadDir . $outputFile;
- copy($outputFile, $uploadFile);
-
- header('Content-Type: application/octet-stream');
- header('Content-Disposition: attachment; filename="' . $outputFile . '"');
- readfile($outputFile);
- unlink($outputFile);
- exit;
- }
-
public function getImageFiles() {
- $imageFiles = glob("image/screenshot_*.jpg");
- if ($imageFiles) rsort($imageFiles); else $imageFiles = [];
- return json_encode($imageFiles);
- }
-
- public function captureVideoSequence($duration = 10) {
- $outputFile = 'sequence_' . date('YmdHis') . '.mp4';
- $src = escapeshellarg($this->videoSrc);
- $logo = escapeshellarg($this->logoPath);
- $dur = intval($duration);
- $command = "ffmpeg -i {$src} -i {$logo} -filter_complex 'overlay=10:10' -t {$dur} -c:v libx264 -preset fast -crf 23 {$outputFile}";
- exec($command, $output, $returnVar);
- if ($returnVar !== 0) return "Fehler";
-
- $uploadDir = "uploads/";
- if (!file_exists($uploadDir)) mkdir($uploadDir, 0777, true);
- $uploadFile = $uploadDir . $outputFile;
- copy($outputFile, $uploadFile);
-
- header('Content-Type: video/mp4');
- header('Content-Disposition: attachment; filename="' . $outputFile . '"');
- readfile($outputFile);
- unlink($outputFile);
- exit;
+ $f = glob("image/screenshot_*.jpg");
+ if ($f) rsort($f);
+ return json_encode($f ?: []);
}
public function getJavaScript() {
@@ -225,2261 +122,541 @@ class WebcamManager {
document.addEventListener('DOMContentLoaded', function () {
var video = document.getElementById('webcam-player');
var videoSrc = '{$this->videoSrc}';
- var bitrateBadge = document.getElementById('bitrate-display');
- var bitrateValue = document.getElementById('bitrate-value');
- var isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
- var isIOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
-
- if(video) {
- video.controls = false;
- if (isIOS) {
- video.src = videoSrc;
- video.setAttribute('playsinline', '');
- video.setAttribute('webkit-playsinline', '');
- video.muted = true;
- if(bitrateBadge) bitrateBadge.style.display = 'none';
- video.addEventListener('loadedmetadata', function() { video.play().catch(console.log); });
- } else if (Hls.isSupported()) {
- var hls = new Hls({ enableWorker: !isMobile, lowLatencyMode: false });
- hls.loadSource(videoSrc);
- hls.attachMedia(video);
- hls.on(Hls.Events.MANIFEST_PARSED, function () {
- if (isMobile) video.muted = true;
- video.play().catch(console.log);
- if(bitrateBadge) bitrateBadge.style.display = 'inline-flex';
- });
- hls.on(Hls.Events.FRAG_LOADED, function(event, data) {
- var bandwidth = hls.bandwidthEstimate;
- if (bandwidth && !isNaN(bandwidth) && bitrateValue) {
- var mbs = bandwidth / 8 / 1024 / 1024;
- if (mbs > 0) bitrateValue.textContent = mbs.toFixed(2);
- }
- });
- }
+ if(video && typeof Hls !== 'undefined' && Hls.isSupported()) {
+ var hls = new Hls();
+ hls.loadSource(videoSrc);
+ hls.attachMedia(video);
+ hls.on(Hls.Events.MANIFEST_PARSED, function () { video.play().catch(()=>{}); });
+ } else if (video) {
+ video.src = videoSrc;
+ video.play().catch(()=>{});
}
- });
- ";
+ });";
}
-
- public function setVideoSrc($src) { $this->videoSrc = $src; }
}
-
-
class VisualCalendarManager {
- private $videoDir;
- private $aiDir;
- private $monthNames;
- private $settingsManager;
+ private $videoDir, $settingsManager;
+ private $months = [1=>'Jan',2=>'Feb',3=>'Mär',4=>'Apr',5=>'Mai',6=>'Jun',7=>'Jul',8=>'Aug',9=>'Sep',10=>'Okt',11=>'Nov',12=>'Dez'];
- // AI-Kategorien mit Icons und Farben
- private $aiCategories = [
- 'sunny' => ['icon' => '☀️', 'name' => 'Sonnig', 'color' => '#FFD700'],
- 'rainy' => ['icon' => '🌧️', 'name' => 'Regen', 'color' => '#4682B4'],
- 'snowy' => ['icon' => '❄️', 'name' => 'Schnee', 'color' => '#E0FFFF'],
- 'planes' => ['icon' => '✈️', 'name' => 'Flugzeuge', 'color' => '#87CEEB'],
- 'birds' => ['icon' => '🐦', 'name' => 'Vögel', 'color' => '#98FB98'],
- 'sunset' => ['icon' => '🌅', 'name' => 'Sonnenuntergang', 'color' => '#FF6347'],
- 'sunrise' => ['icon' => '🌄', 'name' => 'Sonnenaufgang', 'color' => '#FFA07A'],
- 'rainbow' => ['icon' => '🌈', 'name' => 'Regenbogen', 'color' => '#FF69B4'],
- ];
-
- public function __construct($videoDir = './videos/', $aiDir = './ai/', $settingsManager = null) {
+ public function __construct($videoDir = './videos/', $sm = null) {
$this->videoDir = $videoDir;
- $this->aiDir = $aiDir;
- $this->settingsManager = $settingsManager;
- $this->monthNames = [
- 1 => ['de' => 'Januar', 'en' => 'January', 'it' => 'Gennaio', 'fr' => 'Janvier', 'zh' => '一月'],
- 2 => ['de' => 'Februar', 'en' => 'February', 'it' => 'Febbraio', 'fr' => 'Février', 'zh' => '二月'],
- 3 => ['de' => 'März', 'en' => 'March', 'it' => 'Marzo', 'fr' => 'Mars', 'zh' => '三月'],
- 4 => ['de' => 'April', 'en' => 'April', 'it' => 'Aprile', 'fr' => 'Avril', 'zh' => '四月'],
- 5 => ['de' => 'Mai', 'en' => 'May', 'it' => 'Maggio', 'fr' => 'Mai', 'zh' => '五月'],
- 6 => ['de' => 'Juni', 'en' => 'June', 'it' => 'Giugno', 'fr' => 'Juin', 'zh' => '六月'],
- 7 => ['de' => 'Juli', 'en' => 'July', 'it' => 'Luglio', 'fr' => 'Juillet', 'zh' => '七月'],
- 8 => ['de' => 'August', 'en' => 'August', 'it' => 'Agosto', 'fr' => 'Août', 'zh' => '八月'],
- 9 => ['de' => 'September', 'en' => 'September', 'it' => 'Settembre', 'fr' => 'Septembre', 'zh' => '九月'],
- 10 => ['de' => 'Oktober', 'en' => 'October', 'it' => 'Ottobre', 'fr' => 'Octobre', 'zh' => '十月'],
- 11 => ['de' => 'November', 'en' => 'November', 'it' => 'Novembre', 'fr' => 'Novembre', 'zh' => '十一月'],
- 12 => ['de' => 'Dezember', 'en' => 'December', 'it' => 'Dicembre', 'fr' => 'Décembre', 'zh' => '十二月']
- ];
+ $this->settingsManager = $sm;
}
- /**
- * Holt AI-Events für ein bestimmtes Datum
- */
- public function getAiEventsForDate($year, $month, $day) {
- $events = [];
- $dateStr = sprintf('%04d%02d%02d', $year, $month, $day);
+ public function hasVideosForDate($y, $m, $d) {
+ return count(glob($this->videoDir . sprintf("daily_video_%04d%02d%02d_*.mp4", $y, $m, $d))) > 0;
+ }
- foreach ($this->aiCategories as $category => $info) {
- $categoryDir = $this->aiDir . $category . '/';
- if (!is_dir($categoryDir)) continue;
-
- // Suche nach Videos für dieses Datum
- $pattern = $categoryDir . "{$category}_{$dateStr}*.mp4";
- $videos = glob($pattern);
-
- if (!empty($videos)) {
- $events[$category] = [
- 'icon' => $info['icon'],
- 'name' => $info['name'],
- 'color' => $info['color'],
- 'videos' => $videos,
- 'count' => count($videos)
- ];
- }
+ public function getVideosForDate($y, $m, $d) {
+ $vids = [];
+ foreach (glob($this->videoDir . sprintf("daily_video_%04d%02d%02d_*.mp4", $y, $m, $d)) as $v) {
+ $vids[] = ['path' => $v, 'name' => basename($v), 'size' => filesize($v), 'time' => date('H:i', filemtime($v))];
}
-
- return $events;
- }
-
- /**
- * Prüft ob AI-Events für ein Datum existieren
- */
- public function hasAiEventsForDate($year, $month, $day) {
- $dateStr = sprintf('%04d%02d%02d', $year, $month, $day);
-
- foreach (array_keys($this->aiCategories) as $category) {
- $pattern = $this->aiDir . $category . "/{$category}_{$dateStr}*.mp4";
- if (count(glob($pattern)) > 0) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Holt kurze Icon-Liste für Kalender-Anzeige
- */
- public function getAiIconsForDate($year, $month, $day) {
- $icons = [];
- $events = $this->getAiEventsForDate($year, $month, $day);
-
- foreach ($events as $category => $info) {
- $icons[] = $info['icon'];
- }
-
- return $icons;
- }
-
- public function getVideosForDate($year, $month, $day) {
- $videos = [];
- $dateStr = sprintf('%04d%02d%02d', $year, $month, $day);
-
- foreach (glob($this->videoDir . "daily_video_{$dateStr}_*.mp4") as $video) {
- $videos[] = [
- 'path' => $video,
- 'filename' => basename($video),
- 'filesize' => filesize($video),
- 'time' => date('H:i', filemtime($video))
- ];
- }
-
- return $videos;
- }
-
- public function hasVideosForDate($year, $month, $day) {
- $dateStr = sprintf('%04d%02d%02d', $year, $month, $day);
- $pattern = $this->videoDir . "daily_video_{$dateStr}_*.mp4";
- return count(glob($pattern)) > 0;
+ return $vids;
}
public function displayVisualCalendar() {
- $currentYear = isset($_GET['cal_year']) ? intval($_GET['cal_year']) : date('Y');
- $currentMonth = isset($_GET['cal_month']) ? intval($_GET['cal_month']) : date('n');
- $selectedDay = isset($_GET['cal_day']) ? intval($_GET['cal_day']) : null;
+ $cy = isset($_GET['cal_year']) ? intval($_GET['cal_year']) : date('Y');
+ $cm = isset($_GET['cal_month']) ? intval($_GET['cal_month']) : date('n');
+ $sd = isset($_GET['cal_day']) ? intval($_GET['cal_day']) : null;
+ $pip = $this->settingsManager ? $this->settingsManager->get('video_mode.play_in_player') : true;
+ $dl = $this->settingsManager ? $this->settingsManager->get('video_mode.allow_download') : true;
- // Settings für Video-Modus holen
- $playInPlayer = $this->settingsManager ? $this->settingsManager->get('video_mode.play_in_player') : true;
- $allowDownload = $this->settingsManager ? $this->settingsManager->get('video_mode.allow_download') : true;
+ $o = '
';
+ $o .= '
« '.$this->months[$cm].' '.$cy.' »
';
+ $o .= '
';
+ foreach(['Mo','Di','Mi','Do','Fr','Sa','So'] as $wd) $o .= '
'.$wd.'
';
- $output = '
';
+ $fd = mktime(0,0,0,$cm,1,$cy);
+ $dim = date('t', $fd);
+ $dow = date('N', $fd) - 1;
+ for ($i=0; $i<$dow; $i++) $o .= '
';
- // Navigation
- $output .= '
';
- $output .= '◀ ';
- $output .= '
' . $this->monthNames[$currentMonth]['de'] . ' ' . $currentYear . ' ';
- $output .= '▶ ';
- $output .= '';
-
- // AI-Legende
- $output .= '
';
- $output .= '
🤖 AI-Erkennung: ';
- foreach ($this->aiCategories as $cat => $info) {
- $output .= '
' . $info['icon'] . ' ';
+ for ($d=1; $d<=$dim; $d++) {
+ $hv = $this->hasVideosForDate($cy,$cm,$d);
+ $sel = $sd==$d;
+ $td = ($cy==date('Y') && $cm==date('n') && $d==date('j'));
+ $cls = 'cal-day' . ($hv?' has-vid':'') . ($sel?' sel':'') . ($td?' today':'');
+ $o .= '
'.$d.' '.($hv?'📹 ':'').'
';
}
- $output .= '
';
+ $o .= '
';
- // Kalender-Grid
- $output .= '
';
-
- // Wochentage Header
- $weekdays = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
- foreach ($weekdays as $day) {
- $output .= '
' . $day . '
';
- }
-
- // Tage des Monats
- $firstDay = mktime(0, 0, 0, $currentMonth, 1, $currentYear);
- $daysInMonth = date('t', $firstDay);
- $dayOfWeek = date('N', $firstDay) - 1;
-
- // Leere Zellen vor dem ersten Tag
- for ($i = 0; $i < $dayOfWeek; $i++) {
- $output .= '
';
- }
-
- // Tage mit Videos/AI-Events markieren
- for ($day = 1; $day <= $daysInMonth; $day++) {
- $hasVideos = $this->hasVideosForDate($currentYear, $currentMonth, $day);
- $hasAiEvents = $this->hasAiEventsForDate($currentYear, $currentMonth, $day);
- $aiIcons = $this->getAiIconsForDate($currentYear, $currentMonth, $day);
- $isSelected = ($selectedDay == $day);
- $isToday = ($currentYear == date('Y') && $currentMonth == date('n') && $day == date('j'));
-
- $classes = 'calendar-day';
- if ($hasVideos) $classes .= ' has-video';
- if ($hasAiEvents) $classes .= ' has-ai-events';
- if ($isSelected) $classes .= ' selected';
- if ($isToday) $classes .= ' today';
-
- $output .= '
';
- $output .= '
' . $day . ' ';
-
- // Video-Indikator
- if ($hasVideos) {
- $output .= '
📹 ';
- }
-
- // AI-Event-Icons (max 3 anzeigen)
- if (!empty($aiIcons)) {
- $output .= '
';
- $displayIcons = array_slice($aiIcons, 0, 3);
- foreach ($displayIcons as $icon) {
- $output .= '
' . $icon . ' ';
+ if ($sd) {
+ $vids = $this->getVideosForDate($cy,$cm,$sd);
+ $o .= '
📅 '.sprintf('%02d.%02d.%04d',$sd,$cm,$cy).' ';
+ if ($vids) {
+ $o .= '
';
+ foreach ($vids as $v) {
+ $sz = round($v['size']/1024/1024,1);
+ $tk = hash_hmac('sha256', $v['path'], session_id());
+ $o .= '🕐 '.$v['time'].' '.$sz.' MB ';
+ if ($pip) $o .= '▶️ ';
+ if ($dl) $o .= '⬇️ ';
+ $o .= ' ';
}
- if (count($aiIcons) > 3) {
- $output .= '+' . (count($aiIcons) - 3) . ' ';
- }
- $output .= ' ';
- }
-
- $output .= '
';
- }
-
- $output .= '
'; // calendar-grid
-
- // Video-Liste + AI-Events für ausgewählten Tag
- if ($selectedDay) {
- $videos = $this->getVideosForDate($currentYear, $currentMonth, $selectedDay);
- $aiEvents = $this->getAiEventsForDate($currentYear, $currentMonth, $selectedDay);
-
- $output .= '
';
- $output .= '
📅 ' . sprintf('%02d.%02d.%04d', $selectedDay, $currentMonth, $currentYear) . ' ';
-
- // === TAGESVIDEOS ===
- if (!empty($videos)) {
- $output .= '
';
- $output .= '
📹 Tagesvideos ';
- $output .= '
';
-
- foreach ($videos as $video) {
- $sizeInMb = round($video['filesize'] / (1024 * 1024), 2);
- $token = hash_hmac('sha256', $video['path'], session_id());
- $videoUrl = '?download_specific_video=' . urlencode($video['path']) . '&token=' . $token;
-
- $output .= '';
- $output .= '🕐 ' . $video['time'] . ' Uhr ';
- $output .= '' . $sizeInMb . ' MB ';
- $output .= '';
- $output .= ' ';
- }
-
- $output .= ' ';
- $output .= '
';
- }
-
- // === AI-EREIGNISSE ===
- if (!empty($aiEvents)) {
- $output .= '
';
- $output .= '
🤖 AI-erkannte Ereignisse ';
- $output .= '
';
-
- foreach ($aiEvents as $category => $event) {
- $output .= '
';
- $output .= '';
-
- // Videos für dieses Event
- $output .= '
';
-
- $output .= '
'; // ai-event-card
- }
-
- $output .= '
'; // ai-events-grid
- $output .= '
'; // ai-events-section
- }
-
- // Keine Inhalte
- if (empty($videos) && empty($aiEvents)) {
- $output .= '
';
- $output .= '
📭 Keine Videos oder AI-Ereignisse für diesen Tag verfügbar.
';
- $output .= '
';
- }
-
- $output .= '
'; // day-details
- }
-
- $output .= '
'; // visual-calendar-container
-
- return $output;
- }
-
- /**
- * Handler für AI-Video Downloads
- */
- public function handleAiVideoDownload() {
- if (isset($_GET['download_ai_video']) && isset($_GET['token'])) {
- $videoPath = $_GET['download_ai_video'];
- $token = $_GET['token'];
-
- // Token-Validierung
- $expectedToken = hash_hmac('sha256', $videoPath, session_id());
- if (!hash_equals($expectedToken, $token)) {
- echo "Ungültiger Token. Zugriff verweigert.";
- exit;
- }
-
- // Sicherheitsüberprüfung
- $aiDir = realpath($this->aiDir);
- $requestedPath = realpath($videoPath);
-
- if ($requestedPath && strpos($requestedPath, $aiDir) === 0 && file_exists($requestedPath)) {
- $extension = pathinfo($requestedPath, PATHINFO_EXTENSION);
- if (strtolower($extension) !== 'mp4') {
- echo "Nur MP4-Dateien können heruntergeladen werden.";
- exit;
- }
-
- header('Content-Description: File Transfer');
- header('Content-Type: video/mp4');
- header('Content-Disposition: attachment; filename="'.basename($requestedPath).'"');
- header('Expires: 0');
- header('Cache-Control: must-revalidate');
- header('Pragma: public');
- header('Content-Length: ' . filesize($requestedPath));
- readfile($requestedPath);
- exit;
+ $o .= '';
} else {
- echo "Datei nicht gefunden oder ungültiger Dateipfad.";
- exit;
+ $o .= '
Keine Videos.
';
}
+ $o .= '
';
}
+ $o .= '
';
+ return $o;
}
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
class GuestbookManager {
- private $entries = [];
- private $dbFile = 'guestbook.json';
-
- public function __construct() {
- if (file_exists($this->dbFile)) {
- $this->entries = json_decode(file_get_contents($this->dbFile), true);
- }
- }
-
+ private $entries = [], $file = 'guestbook.json';
+ public function __construct() { if (file_exists($this->file)) $this->entries = json_decode(file_get_contents($this->file), true) ?? []; }
public function handleFormSubmission() {
- if (isset($_POST['guestbook'], $_POST['guest-name'], $_POST['guest-message'])) {
- $this->addEntry($_POST['guest-name'], $_POST['guest-message']);
- $this->saveEntries();
+ if (isset($_POST['guestbook'],$_POST['guest-name'],$_POST['guest-message'])) {
+ $this->entries[] = ['name'=>htmlspecialchars($_POST['guest-name']),'message'=>htmlspecialchars($_POST['guest-message']),'date'=>date('Y-m-d H:i:s')];
+ file_put_contents($this->file, json_encode($this->entries));
}
}
-
- private function addEntry($name, $message) {
- $this->entries[] = [
- 'name' => $name,
- 'message' => $message,
- 'date' => date('Y-m-d H:i:s')
- ];
- }
-
- public function deleteEntry($index) {
- if (isset($this->entries[$index])) {
- unset($this->entries[$index]);
- $this->entries = array_values($this->entries); // Re-indizieren des Arrays
- $this->saveEntries();
- return true;
+ public function deleteEntry($i) { if (isset($this->entries[$i])) { unset($this->entries[$i]); $this->entries = array_values($this->entries); file_put_contents($this->file, json_encode($this->entries)); return true; } return false; }
+ public function displayForm() { return '
'; }
+ public function displayEntries($admin=false) {
+ $o = '
';
+ foreach ($this->entries as $i=>$e) {
+ $o .= '
'.$e['name'].' '.$e['message'].'
'.$e['date'].' ';
+ if ($admin) $o .= '
X ';
+ $o .= '
';
}
- return false;
+ return $o.'
';
}
-
-
-
- private function saveEntries() {
- file_put_contents($this->dbFile, json_encode($this->entries));
- }
-
- public function displayForm() {
- return '
-
-
-
-
- Name:
-
-
-
- Nachricht:
-
-
-
- Eintrag hinzufügen
-
-
- ';
- }
-public function displayEntries($isAdmin = false) {
- $output = '
';
- foreach ($this->entries as $index => $entry) {
- $output .= "
-
-
{$entry['name']}
-
{$entry['message']}
-
{$entry['date']}";
- if ($isAdmin) {
- $output .= "
-
-
- Löschen
- ";
- }
-
- }
- $output .= '
';
- return $output;
}
-
-}
-
-
class ContactManager {
- private $adminEmail = 'metacube@gmail.com';
- private $feedbackFile = 'feedbacks.json';
- private $gmailUser = 'metacube@gmail.com';
- private $gmailAppPassword = 'qggk hsxz fdkq jgxa';
-
- public function displayForm() {
- return '
-
-
-
- Name:
-
-
-
-
- E-Mail:
-
-
-
-
- Nachricht:
-
-
-
-
- Nachricht senden
-
-
-
';
- }
-
- public function handleSubmission($name, $email, $message) {
- if (empty($name) || empty($email) || empty($message)) {
- return ['success' => false, 'message' => 'Alle Felder sind erforderlich'];
- }
-
- if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
- return ['success' => false, 'message' => 'Ungültige E-Mail-Adresse'];
- }
-
- if (strlen($message) < 10) {
- return ['success' => false, 'message' => 'Nachricht zu kurz (mindestens 10 Zeichen)'];
- }
-
- $name = htmlspecialchars(trim($name), ENT_QUOTES, 'UTF-8');
- $email = filter_var(trim($email), FILTER_SANITIZE_EMAIL);
- $message = htmlspecialchars(trim($message), ENT_QUOTES, 'UTF-8');
-
- $feedback = [
- 'name' => $name,
- 'email' => $email,
- 'message' => $message,
- 'date' => date('Y-m-d H:i:s'),
- 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
- 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown'
- ];
-
- $feedbacks = file_exists($this->feedbackFile)
- ? json_decode(file_get_contents($this->feedbackFile), true)
- : [];
-
- if (!is_array($feedbacks)) $feedbacks = [];
-
- $feedbacks[] = $feedback;
- file_put_contents($this->feedbackFile, json_encode($feedbacks, JSON_PRETTY_PRINT));
-
- $mailSent = $this->sendEmailViaGmail($name, $email, $message, $feedback['date'], $feedback['ip']);
-
- if ($mailSent) {
- return ['success' => true, 'message' => 'Vielen Dank! Ihre Nachricht wurde gesendet.'];
- } else {
- error_log("Mail-Fehler: Nachricht von {$email} konnte nicht gesendet werden");
- return ['success' => false, 'message' => 'Nachricht wurde gespeichert, aber E-Mail konnte nicht gesendet werden.'];
- }
- }
-
- private function sendEmailViaGmail($name, $email, $message, $date, $ip) {
- $mail = new PHPMailer(true);
-
- try {
- $mail->SMTPDebug = 2;
- $mail->Debugoutput = function($str, $level) {
- error_log("PHPMailer Debug: $str");
- };
-
- $mail->isSMTP();
- $mail->Host = 'smtp.gmail.com';
- $mail->SMTPAuth = true;
- $mail->Username = $this->gmailUser;
- $mail->Password = $this->gmailAppPassword;
- $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
- $mail->Port = 587;
-
- $mail->setFrom($this->gmailUser, 'Aurora Livecam');
- $mail->addAddress($this->adminEmail);
- $mail->addReplyTo($email, $name);
-
- $mail->isHTML(true);
- $mail->CharSet = 'UTF-8';
- $mail->Subject = '🔔 Neue Kontaktanfrage von ' . $name;
- $mail->Body = $this->getEmailTemplate($name, $email, $message, $date, $ip);
-
- $mail->send();
- return true;
- } catch (Exception $e) {
- error_log("PHPMailer Error: {$mail->ErrorInfo}");
- return false;
- }
- }
-
- public function deleteFeedback($index) {
- if (!file_exists($this->feedbackFile)) return false;
-
- $feedbacks = json_decode(file_get_contents($this->feedbackFile), true);
- if (isset($feedbacks[$index])) {
- unset($feedbacks[$index]);
- $feedbacks = array_values($feedbacks);
- file_put_contents($this->feedbackFile, json_encode($feedbacks, JSON_PRETTY_PRINT));
- return true;
- }
- return false;
- }
-
- private function getEmailTemplate($name, $email, $message, $date, $ip) {
- return "
-
-
-
-
-
-
-
-
-
-
-
👤 Name: {$name}
-
-
💬 Nachricht:
-
" . nl2br($message) . "
-
-
-
-
-
- ";
+ private $file = 'feedbacks.json';
+ public function displayForm() { return '
Name: E-Mail: Nachricht: Senden
'; }
+ public function handleSubmission($n,$e,$m) {
+ if (!$n||!$e||!$m) return ['success'=>false,'message'=>'Alle Felder ausfüllen'];
+ $fb = ['name'=>htmlspecialchars($n),'email'=>filter_var($e,FILTER_SANITIZE_EMAIL),'message'=>htmlspecialchars($m),'date'=>date('Y-m-d H:i:s'),'ip'=>$_SERVER['REMOTE_ADDR']??''];
+ $all = file_exists($this->file) ? json_decode(file_get_contents($this->file),true) : [];
+ $all[] = $fb;
+ file_put_contents($this->file, json_encode($all, JSON_PRETTY_PRINT));
+ return ['success'=>true,'message'=>'Nachricht gesendet!'];
}
+ public function deleteFeedback($i) { $all = json_decode(file_get_contents($this->file),true); if (isset($all[$i])) { unset($all[$i]); file_put_contents($this->file, json_encode(array_values($all),JSON_PRETTY_PRINT)); return true; } return false; }
}
-
class AdminManager {
- public function isAdmin() {
- return isset($_SESSION['admin']) && $_SESSION['admin'] === true;
- }
-
- public function handleLogin($username, $password) {
- if ($username === 'admin' && $password === 'sonne4000$$$$Q') {
- $_SESSION['admin'] = true;
- return true;
- }
- return false;
- }
-
- public function handleImageUpload($file) {
- if (!$this->isAdmin()) return false;
- if (!isset($file['tmp_name']) || empty($file['tmp_name'])) { echo "Keine Datei."; return false; }
-
- $target_dir = "uploads/";
- if (!file_exists($target_dir)) mkdir($target_dir, 0777, true);
-
- $target_file = $target_dir . basename($file["name"]);
- $imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
-
- $check = @getimagesize($file["tmp_name"]);
- if($check === false) { echo "Kein Bild."; return false; }
- if ($file["size"] > 5000000) { echo "Zu groß (>5MB)."; return false; }
- if(!in_array($imageFileType, ['jpg','png','jpeg','gif'])) { echo "Falsches Format."; return false; }
-
- if (move_uploaded_file($file["tmp_name"], $target_file)) {
- echo "
✅ Bild erfolgreich hochgeladen.
";
- return true;
- } else {
- echo "Upload Fehler.";
- return false;
- }
- }
-
- public function displayLoginForm() {
- return '
-
-
- Benutzername:
- Passwort:
- Einloggen
- ';
- }
-
+ public function isAdmin() { return isset($_SESSION['admin']) && $_SESSION['admin'] === true; }
+ public function handleLogin($u,$p) { if ($u==='admin' && $p==='sonne4000$$$$Q') { $_SESSION['admin']=true; return true; } return false; }
+ public function displayLoginForm() { return '
User: Pass: Login '; }
public function displayAdminContent() {
global $settingsManager;
-
- $feedbacks = json_decode(file_get_contents('feedbacks.json') ?: '[]', true);
-
- // NEUES SETTINGS PANEL
- $output = '
';
- $output .= '
⚙️ Anzeige-Einstellungen ';
-
- // Zuschauer-Anzeige Settings
- $output .= '
';
- $output .= '
👥 Zuschauer-Anzeige ';
-
- $output .= '
';
- $output .= '
Zuschauer-Anzahl anzeigen ';
- $output .= '
';
- $output .= '';
- $output .= ' get('viewer_display.enabled') ? 'checked' : '') . '>';
- $output .= ' ';
- $output .= ' ';
- $output .= '
';
- $output .= '
';
-
- $output .= '
';
- $output .= '
Mindestanzahl für Anzeige ';
- $output .= '
';
- $output .= ' ';
- $output .= '
';
- $output .= '
';
- $output .= '
'; // settings-group
-
- // Video-Modus Settings
- $output .= '
';
- $output .= '
🎬 Video-Modus ';
-
- $output .= '
';
- $output .= '
Videos im Player abspielen ';
- $output .= '
';
- $output .= '';
- $output .= ' get('video_mode.play_in_player') ? 'checked' : '') . '>';
- $output .= ' ';
- $output .= ' ';
- $output .= '
';
- $output .= '
';
-
- $output .= '
';
- $output .= '
Download erlauben ';
- $output .= '
';
- $output .= '';
- $output .= ' get('video_mode.allow_download') ? 'checked' : '') . '>';
- $output .= ' ';
- $output .= ' ';
- $output .= '
';
- $output .= '
';
- $output .= '
'; // settings-group
-
- $output .= '
'; // admin-settings-panel
-
- // Bestehender Admin-Content
- $output .= '
';
- $output .= '
📩 Posteingang (Kontaktformular) ';
-
- if (empty($feedbacks)) {
- $output .= '
Keine Nachrichten vorhanden.
';
- } else {
- $output .= '
';
- foreach ($feedbacks as $index => $feedback) {
- $ip = isset($feedback['ip']) ? $feedback['ip'] : 'Unbekannt';
-
- $output .= "
";
- $output .= "
";
- $output .= "
";
-
- $output .= "
-
-
- 🗑️ Löschen
- ";
- $output .= "
";
-
- $output .= "
{$feedback['message']}
";
- $output .= "
📅 {$feedback['date']} | IP: {$ip} ";
- $output .= "
";
- }
- $output .= '
';
+ $o = '
';
+ $o .= '
📩 Nachrichten ';
+ $msgs = file_exists('feedbacks.json') ? json_decode(file_get_contents('feedbacks.json'),true) : [];
+ foreach ($msgs as $i=>$m) {
+ $o .= '
'.$m['name'].' ('.$m['email'].')
'.$m['message'].'
'.$m['date'].' ';
+ $o .= '
X ';
}
- $output .= '
';
-
- $output .= '
';
- $output .= '
🖼️ Bildergalerie verwalten ';
-
- $output .= $this->displayGalleryImages(true);
-
- $output .= '⬆️ Neues Bild hochladen
-
-
-
- ';
- $output .= '';
-
- $output .= '
';
- $output .= '
📲 Social Media Links
-
-
-
- Facebook
- Instagram
- TikTok
-
-
- Link aktualisieren
- ';
- $output .= '';
-
- return $output;
+ if (!$msgs) $o .= '
Keine Nachrichten.
';
+ $o .= '
';
+ return $o;
}
-
- public function displayGalleryImages($isAdmin = false) {
- $output = '
';
- $files = glob("uploads/*.{jpg,jpeg,png,gif}", GLOB_BRACE);
-
- if ($files) {
- foreach($files as $file) {
- $filename = basename($file);
- $output .= '
';
- $output .= '
';
-
- if ($isAdmin) {
- $output .= '
-
-
-
- X
- ';
- }
-
- $output .= '
';
- }
- } else {
- $output .= '
Keine Bilder in der Galerie.
';
- }
- $output .= '
';
- return $output;
- }
-
- public function handleSocialMediaUpdate($platform, $url) {
- $socialLinks = json_decode(file_get_contents('social_links.json') ?: '{}', true);
- $socialLinks[$platform] = $url;
- file_put_contents('social_links.json', json_encode($socialLinks));
+ public function displayGalleryImages() {
+ $o = '
';
+ foreach (glob("uploads/*.{jpg,jpeg,png,gif}",GLOB_BRACE) as $f) $o .= '
';
+ return $o.'
';
}
}
-
class VideoArchiveManager {
- private $videoDir;
- private $monthNames;
-
- public function __construct($videoDir = './videos/') {
- $this->videoDir = $videoDir;
- $this->monthNames = [
- '01' => 'Januar', '02' => 'Februar', '03' => 'März', '04' => 'April',
- '05' => 'Mai', '06' => 'Juni', '07' => 'Juli', '08' => 'August',
- '09' => 'September', '10' => 'Oktober', '11' => 'November', '12' => 'Dezember'
- ];
- }
-
- public function getVideosGroupedByDate() {
- $videos = [];
-
- foreach (glob($this->videoDir . 'daily_video_*.mp4') as $video) {
- if (preg_match('/daily_video_(\d{8})_\d{6}\.mp4/', basename($video), $matches)) {
- $dateStr = $matches[1];
- $year = substr($dateStr, 0, 4);
- $month = substr($dateStr, 4, 2);
- $day = substr($dateStr, 6, 2);
-
- $videos[$year][$month][] = [
- 'path' => $video,
- 'filename' => basename($video),
- 'day' => $day,
- 'filesize' => filesize($video),
- 'modified' => filemtime($video)
- ];
- }
- }
-
- foreach ($videos as $year => $months) {
- foreach ($months as $month => $days) {
- usort($videos[$year][$month], function($a, $b) {
- return $b['day'] - $a['day'];
- });
- }
- }
-
- return $videos;
- }
-
+ private $dir;
+ public function __construct($d='./videos/') { $this->dir = $d; }
public function handleSpecificVideoDownload() {
- if (isset($_GET['download_specific_video']) && isset($_GET['token'])) {
- $videoPath = $_GET['download_specific_video'];
- $token = $_GET['token'];
-
- $expectedToken = hash_hmac('sha256', $videoPath, session_id());
- if (!hash_equals($expectedToken, $token)) {
- echo "Ungültiger Token. Zugriff verweigert.";
- exit;
- }
-
- $videoDir = realpath($this->videoDir);
- $requestedPath = realpath($videoPath);
-
- if ($requestedPath && strpos($requestedPath, $videoDir) === 0 && file_exists($requestedPath)) {
- $extension = pathinfo($requestedPath, PATHINFO_EXTENSION);
- if (strtolower($extension) !== 'mp4') {
- echo "Nur MP4-Dateien können heruntergeladen werden.";
- exit;
- }
-
- header('Content-Description: File Transfer');
+ if (isset($_GET['download_specific_video'],$_GET['token'])) {
+ $p = $_GET['download_specific_video'];
+ if (!hash_equals(hash_hmac('sha256',$p,session_id()), $_GET['token'])) { echo "Invalid"; exit; }
+ $rp = realpath($p);
+ $rd = realpath($this->dir);
+ if ($rp && strpos($rp,$rd)===0 && file_exists($rp)) {
header('Content-Type: video/mp4');
- header('Content-Disposition: attachment; filename="'.basename($requestedPath).'"');
- header('Expires: 0');
- header('Cache-Control: must-revalidate');
- header('Pragma: public');
- header('Content-Length: ' . filesize($requestedPath));
- readfile($requestedPath);
- exit;
- } else {
- echo "Datei nicht gefunden oder ungültiger Dateipfad.";
+ header('Content-Disposition: attachment; filename="'.basename($rp).'"');
+ header('Content-Length: '.filesize($rp));
+ readfile($rp);
exit;
}
+ echo "Not found"; exit;
}
}
}
-
$webcamManager = new WebcamManager();
-$imageFilesJson = $webcamManager->getImageFiles();
$guestbookManager = new GuestbookManager();
$contactManager = new ContactManager();
$adminManager = new AdminManager();
-
$videoArchiveManager = new VideoArchiveManager('./videos/');
$videoArchiveManager->handleSpecificVideoDownload();
-// AI-Video Download Handler
-if (isset($_GET['download_ai_video']) && isset($_GET['token'])) {
- $videoPath = $_GET['download_ai_video'];
- $token = $_GET['token'];
-
- $expectedToken = hash_hmac('sha256', $videoPath, session_id());
- if (hash_equals($expectedToken, $token)) {
- $aiDir = realpath('./ai/');
- $requestedPath = realpath($videoPath);
-
- if ($requestedPath && strpos($requestedPath, $aiDir) === 0 && file_exists($requestedPath)) {
- header('Content-Description: File Transfer');
- header('Content-Type: video/mp4');
- header('Content-Disposition: attachment; filename="'.basename($requestedPath).'"');
- header('Expires: 0');
- header('Cache-Control: must-revalidate');
- header('Pragma: public');
- header('Content-Length: ' . filesize($requestedPath));
- readfile($requestedPath);
- exit;
- }
- }
- echo "Download fehlgeschlagen.";
- exit;
-}
-
-if (isset($_GET['action'])) {
- switch ($_GET['action']) {
- case 'snapshot':
- $webcamManager->captureSnapshot();
- break;
- case 'sequence':
- $webcamManager->captureVideoSequence();
- break;
- }
-}
-
-
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- // Viewer Heartbeat
- if (isset($_POST['action']) && $_POST['action'] === 'viewer_heartbeat') {
- $viewerCounter->handleHeartbeat();
+ if (isset($_POST['action']) && $_POST['action'] === 'viewer_heartbeat') $viewerCounter->handleHeartbeat();
+ if (isset($_POST['guestbook'])) { $guestbookManager->handleFormSubmission(); header("Location: ".$_SERVER['PHP_SELF']."#guestbook"); exit; }
+ if (isset($_POST['contact'])) {
+ $r = $contactManager->handleSubmission($_POST['name'],$_POST['email'],$_POST['message']);
+ if (isset($_SERVER['HTTP_X_REQUESTED_WITH'])) { header('Content-Type: application/json'); echo json_encode($r); exit; }
+ header('Location: '.$_SERVER['PHP_SELF'].'#kontakt'); exit;
}
-
- // GÄSTEBUCH
- if (isset($_POST['guestbook'])) {
- $guestbookManager->handleFormSubmission();
- header("Location: " . $_SERVER['PHP_SELF'] . "#guestbook");
- exit;
- }
-
- // KONTAKTFORMULAR
- elseif (isset($_POST['contact'])) {
- $result = $contactManager->handleSubmission($_POST['name'], $_POST['email'], $_POST['message']);
-
- if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
- header('Content-Type: application/json');
- echo json_encode($result);
- exit;
- }
- $_SESSION['contact_result'] = $result;
- header('Location: ' . $_SERVER['PHP_SELF'] . '#kontakt');
- exit;
- }
-
- // ADMIN LOGIN
- elseif (isset($_POST['admin-login'])) {
- $adminManager->handleLogin($_POST['username'], $_POST['password']);
- header('Location: ' . $_SERVER['PHP_SELF'] . '#admin');
- exit;
- }
-
- // ADMIN AKTIONEN
- elseif ($adminManager->isAdmin()) {
- if (isset($_POST['action']) && $_POST['action'] === 'delete_guestbook' && isset($_POST['delete_entry'])) {
- $guestbookManager->deleteEntry(intval($_POST['delete_entry']));
- header("Location: " . $_SERVER['PHP_SELF'] . "#guestbook");
- exit;
- }
-
- if (isset($_POST['action']) && $_POST['action'] === 'delete_feedback' && isset($_POST['delete_index'])) {
- $contactManager->deleteFeedback(intval($_POST['delete_index']));
- header("Location: " . $_SERVER['PHP_SELF'] . "#admin");
- exit;
- }
-
- if (isset($_POST['action']) && $_POST['action'] === 'delete_image' && isset($_POST['image_name'])) {
- $filename = basename($_POST['image_name']);
- $filepath = "uploads/" . $filename;
- if (file_exists($filepath)) { unlink($filepath); }
- header("Location: " . $_SERVER['PHP_SELF'] . "#admin");
- exit;
- }
-
- if (isset($_POST['update-social-media'])) {
- $adminManager->handleSocialMediaUpdate($_POST['social-platform'], $_POST['social-url']);
- header("Location: " . $_SERVER['PHP_SELF'] . "#admin");
- exit;
- }
-
- if (isset($_FILES["fileToUpload"])) {
- $adminManager->handleImageUpload($_FILES["fileToUpload"]);
- }
+ if (isset($_POST['admin-login'])) { $adminManager->handleLogin($_POST['username'],$_POST['password']); header('Location: '.$_SERVER['PHP_SELF'].'#admin'); exit; }
+ if ($adminManager->isAdmin()) {
+ if (isset($_POST['action']) && $_POST['action']==='delete_guestbook') { $guestbookManager->deleteEntry(intval($_POST['delete_entry'])); header("Location: ".$_SERVER['PHP_SELF']."#guestbook"); exit; }
+ if (isset($_POST['action']) && $_POST['action']==='delete_feedback') { $contactManager->deleteFeedback(intval($_POST['delete_index'])); header("Location: ".$_SERVER['PHP_SELF']."#admin"); exit; }
}
}
-// Viewer-Anzeige Einstellungen für JavaScript
-$viewerCount = $viewerCounter->getInitialCount();
-$showViewers = $settingsManager->shouldShowViewers($viewerCount);
-$minViewersToShow = $settingsManager->get('viewer_display.min_viewers');
-?>
-
-
-
-
+$vc = $viewerCounter->getInitialCount();
+$sv = $settingsManager->get('viewer_display.enabled') && $vc >= $settingsManager->get('viewer_display.min_viewers');
+$mv = $settingsManager->get('viewer_display.min_viewers');
+?>
-
-
-
-
Aurora Livecam Zürich Oberland | Live Wetter Webcam Schweiz 24/7
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
Aurora Livecam
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
- Willkommen bei Aurora Wetter Livecam
-
-
-
-
- Erleben Sie faszinierende Ausblicke der Züricher Region - in Echtzeit!
-
-
-
+
+Aurora Wetter Livecam
+Faszinierende Ausblicke aus dem Zürcher Oberland
+
-
-
-
Unsere Empfehlungen
-
-
-
+
+
+
+
+displayWebcam(); ?>
+
+
+
+−
+⟲
++
+
+
-
-
-
-
-
- displayWebcam(); ?>
+
+
+
+
+
+--:--:--
+1x
+ Live
+
+
-
-
-
-
-
+
Zurück zu Live
-
-
-
-
-
-
-
+
+displayStreamStats(); ?>
+
Zuschauer
+
-
-
-
-
-
-
-
-
- displayStreamStats(); ?>
-
-
-
-
-
- Zuschauer
-
-
-
-
-
-
-
-
-
+
+
-
-
-
Videoarchiv Tagesvideos
- displayVisualCalendar();
- ?>
-
+
+
📅 Videoarchiv
+displayVisualCalendar(); ?>
+
-
-
-
-
Kamera-Blickrichtung
-
-
-
-
-
-
📍 Ungefährer Standort
-
⛰️ Höhe: ca. 616 m ü.M.
-
🧭 Blickrichtung: Südwest (SW)
-
📍 Region: Zürich Oberland
-
-
-
-
-
-
-
-
-
-
- Folge uns und kopiere den Code und sende es deinen Freunden
-
-
-
-
- Klicke auf den QR-Code, um die URL zu kopieren
-
-
-
-
-
-
-
Gästebuch
- displayForm();
- echo $guestbookManager->displayEntries($adminManager->isAdmin());
- ?>
-
+
+
Gästebuch
+displayForm(); echo $guestbookManager->displayEntries($adminManager->isAdmin()); ?>
+
-
-
-
Kontakt
-
- Haben Sie Fragen, Anregungen oder möchten uns unterstützen? Wir freuen uns auf Ihre Nachricht!
-
- displayForm(); ?>
-
+
+
Kontakt
+displayForm(); ?>
+
-
-
-
Bildergalerie
-
-
- displayGalleryImages(); ?>
-
-
-
+
+
Galerie
+displayGalleryImages(); ?>
+
-
-
-
-
Über unser Projekt
-
-
-
- Aurora Wetter Livecam ist ein Herzensprojekt von Wetterbegeisterten. Wir möchten Ihnen die Schönheit der Natur und Faszination des Wetters näher bringen.
-
-
Dazu betreiben wir seit 2010 rund um die Uhr hochauflösende Webcams. Besonders stolz sind wir auf einzigartige Einblicke, wie z.B. die Trainingsflüge der Patrouille Suisse jeden Montagmorgen.
-
-
-
-
-
-
-isAdmin()): ?>
+isAdmin()): ?>
-
-
Admin-Bereich
- displayAdminContent(); ?>
-
+
+
⚙️ Admin
+displayAdminContent(); ?>
+
-
-
-
Admin Login
- displayLoginForm(); ?>
-
+
+
+
Admin Login
+displayLoginForm(); ?>
+
-
-
-
-
Impressum
-
Aurora Wetter Livecam
-
M. Kessler
-
Dürnten, Schweiz
-
Anfragen per Kontaktformular
-
-
-
-
-
-
-
-
×
-
❮
-
❯
-
-
-
Download
+
+
×
+
-
-
-
-
-
-
-
-
-
-
-isAdmin()): ?>
-
+}
+document.getElementById('s-viewer')?.addEventListener('change',e=>save('viewer_display.enabled',e.target.checked));
+document.getElementById('s-min')?.addEventListener('change',e=>save('viewer_display.min_viewers',e.target.value));
+document.getElementById('s-play')?.addEventListener('change',e=>save('video_mode.play_in_player',e.target.checked));
+document.getElementById('s-dl')?.addEventListener('change',e=>save('video_mode.allow_download',e.target.checked));
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-