diff --git a/aurora-livecam/indexmiau.php b/aurora-livecam/indexmiau.php
new file mode 100644
index 0000000..04668ba
--- /dev/null
+++ b/aurora-livecam/indexmiau.php
@@ -0,0 +1,721 @@
+ 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;
+ foreach (glob($videoDir . '*.mp4') as $video) {
+ $mtime = filemtime($video);
+ if ($mtime > $latestTime) { $latestTime = $mtime; $latestVideo = $video; }
+ }
+ if ($latestVideo) {
+ header('Content-Type: application/octet-stream');
+ header('Content-Disposition: attachment; filename="'.basename($latestVideo).'"');
+ header('Content-Length: ' . filesize($latestVideo));
+ readfile($latestVideo);
+ exit;
+ }
+ echo "Kein Video gefunden.";
+ exit;
+}
+
+$oldDomains = ['www.aurora-wetter-lifecam.ch', 'www.aurora-wetter-livecam.ch'];
+$newDomain = 'www.aurora-weather-livecam.com';
+if (in_array($_SERVER['HTTP_HOST'] ?? '', $oldDomains)) {
+ $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
+ 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', 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;
+
+ public function handleHeartbeat() {
+ $ip = md5($_SERVER['REMOTE_ADDR'] . ($_SERVER['HTTP_USER_AGENT'] ?? ''));
+ $now = time();
+ $viewers = file_exists($this->file) ? json_decode(file_get_contents($this->file), true) ?? [] : [];
+ $viewers[$ip] = $now;
+ $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' => count($active)]);
+ exit;
+ }
+
+ public function getInitialCount() {
+ if (file_exists($this->file)) {
+ return max(1, count(json_decode(file_get_contents($this->file), true) ?? []));
+ }
+ return 1;
+ }
+}
+
+$viewerCounter = new ViewerCounter();
+
+class WebcamManager {
+ private $videoSrc = 'test_video.m3u8';
+
+ public function displayWebcam() {
+ return '';
+ }
+
+ public function displayStreamStats() {
+ return '
+ 0.00 MBit/s
+
';
+ }
+
+ public function getImageFiles() {
+ $f = glob("image/screenshot_*.jpg");
+ if ($f) rsort($f);
+ return json_encode($f ?: []);
+ }
+
+ public function getJavaScript() {
+ return "
+ document.addEventListener('DOMContentLoaded', function () {
+ var video = document.getElementById('webcam-player');
+ var videoSrc = '{$this->videoSrc}';
+ 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(()=>{});
+ }
+ });";
+ }
+}
+
+class VisualCalendarManager {
+ 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'];
+
+ public function __construct($videoDir = './videos/', $sm = null) {
+ $this->videoDir = $videoDir;
+ $this->settingsManager = $sm;
+ }
+
+ public function hasVideosForDate($y, $m, $d) {
+ return count(glob($this->videoDir . sprintf("daily_video_%04d%02d%02d_*.mp4", $y, $m, $d))) > 0;
+ }
+
+ 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 $vids;
+ }
+
+ public function displayVisualCalendar() {
+ $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;
+
+ $o = '';
+ $o .= '
'.$this->months[$cm].' '.$cy.'
';
+ $o .= '
';
+ foreach(['Mo','Di','Mi','Do','Fr','Sa','So'] as $wd) $o .= '
'.$wd.'
';
+
+ $fd = mktime(0,0,0,$cm,1,$cy);
+ $dim = date('t', $fd);
+ $dow = date('N', $fd) - 1;
+ for ($i=0; $i<$dow; $i++) $o .= '
';
+
+ 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?'📹':'').'
';
+ }
+ $o .= '
';
+
+ 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 .= '
';
+ }
+ $o .= '
';
+ } else {
+ $o .= '
Keine Videos.
';
+ }
+ $o .= '
';
+ }
+ $o .= '
';
+ return $o;
+ }
+}
+
+class GuestbookManager {
+ 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->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));
+ }
+ }
+ 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 .= '
';
+ $o .= '
';
+ }
+ return $o.'
';
+ }
+}
+
+class ContactManager {
+ private $file = 'feedbacks.json';
+ public function displayForm() { return ''; }
+ 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($u,$p) { if ($u==='admin' && $p==='sonne4000$$$$Q') { $_SESSION['admin']=true; return true; } return false; }
+ public function displayLoginForm() { return ''; }
+ public function displayAdminContent() {
+ global $settingsManager;
+ $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 .= '
';
+ }
+ if (!$msgs) $o .= '
Keine Nachrichten.
';
+ $o .= '
';
+ return $o;
+ }
+ public function displayGalleryImages() {
+ $o = '';
+ foreach (glob("uploads/*.{jpg,jpeg,png,gif}",GLOB_BRACE) as $f) $o .= '

';
+ return $o.'
';
+ }
+}
+
+class VideoArchiveManager {
+ private $dir;
+ public function __construct($d='./videos/') { $this->dir = $d; }
+ public function handleSpecificVideoDownload() {
+ 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($rp).'"');
+ header('Content-Length: '.filesize($rp));
+ readfile($rp);
+ exit;
+ }
+ echo "Not found"; exit;
+ }
+ }
+}
+
+$webcamManager = new WebcamManager();
+$guestbookManager = new GuestbookManager();
+$contactManager = new ContactManager();
+$adminManager = new AdminManager();
+$videoArchiveManager = new VideoArchiveManager('./videos/');
+$videoArchiveManager->handleSpecificVideoDownload();
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ 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;
+ }
+ 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; }
+ }
+}
+
+$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
+
+
+
+
+
+
+
+
+
+Aurora Wetter Livecam
+Faszinierende Ausblicke aus dem Zürcher Oberland
+
+
+
+
+
+
+displayWebcam(); ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+--:--:--
+
+
+
+
+
+
+
+
+displayStreamStats(); ?>
+
Zuschauer
+
+
+
+
+
+
+
+
+
📅 Videoarchiv
+displayVisualCalendar(); ?>
+
+
+
+
+
+
Gästebuch
+displayForm(); echo $guestbookManager->displayEntries($adminManager->isAdmin()); ?>
+
+
+
+
+
+
Kontakt
+displayForm(); ?>
+
+
+
+
+
+
Galerie
+displayGalleryImages(); ?>
+
+
+
+isAdmin()): ?>
+
+
+
⚙️ Admin
+displayAdminContent(); ?>
+
+
+
+
+
+
Admin Login
+displayLoginForm(); ?>
+
+
+
+
+
+
+
+
×
+
![]()
+
+
+
+
+