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 ''; + } + + 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 .= ''; + } 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 .= '

⚙️ Einstellungen

'; + $o .= '
get('viewer_display.enabled')?'checked':'').'>
'; + $o .= '
'; + $o .= '
get('video_mode.play_in_player')?'checked':'').'>
'; + $o .= '
get('video_mode.allow_download')?'checked':'').'>
'; + $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 = ''; + } +} + +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
+
+ +
+📷 Snapshot + +⬇️ Tagesvideo +
+
+
+ +
+
+

📅 Videoarchiv

+displayVisualCalendar(); ?> +
+
+ +
+
+

Gästebuch

+displayForm(); echo $guestbookManager->displayEntries($adminManager->isAdmin()); ?> +
+
+ +
+
+

Kontakt

+displayForm(); ?> +
+
+ + + +isAdmin()): ?> +
+
+

⚙️ Admin

+displayAdminContent(); ?> +
+
+ +
+
+

Admin Login

+displayLoginForm(); ?> +
+
+ + + + + + + + +