Files
WKVS/www/externe-geraete/audio.php
T
2026-07-24 21:49:40 +02:00

323 lines
10 KiB
PHP

<?php
if (!isset($segments) || !defined('APP_ROUTER')) {
http_response_code(403);
include $baseDir . "/error-pages/403.php";
exit;
}
$type = $segments[1] ?? null;
$requested_geraet = htmlspecialchars($segments[2] ?? '');
$allowed_types = ["audioplayer"];
if (!in_array($type, $allowed_types)) {
http_response_code(400);
include $baseDir . "/error-pages/400.html";
exit;
}
$baseDir = $_SERVER['DOCUMENT_ROOT'];
require_once $baseDir . '/../scripts/session_functions.php';
ini_wkvs_session(true);
$csrf_token = $_SESSION['csrf_token'] ?? '';
require $baseDir . '/../scripts/websocket/ws-create-token.php';
$WSaccesstype = "audio";
$WSaccessPermission = "R";
require_once $baseDir . '/../scripts/db/db-verbindung-script-guest.php';
require_once $baseDir . '/../scripts/db/db-functions.php';
require_once $baseDir . '/../scripts/db/db-tables.php';
$stmt = $guest->prepare("SELECT `name`, `id` FROM $db_tabelle_disziplinen WHERE `audiofile` = '1' ORDER BY start_index ASC");
if (!$stmt->execute()) {
http_response_code(500);
exit;
}
$result = $stmt->get_result();
$disciplines = $result->fetch_all(MYSQLI_ASSOC);
$lowerDisciplines = array_change_key_case(
array_column($disciplines, 'id', 'name'),
CASE_LOWER
);
$disciplines_indexed = array_column($disciplines, 'name', 'id');
if (!array_key_exists($requested_geraet, $lowerDisciplines)) {
http_response_code(400);
$message = 'Das gesuchte Gerät kann nicht gefunden werden';
include $baseDir . "/error-pages/400.php";
exit;
}
if (!isset($lowerDisciplines[$requested_geraet])) {
http_response_code(500);
include $baseDir . "/error-pages/500.html";
exit;
}
$geraetId = $lowerDisciplines[$requested_geraet];
$WSaccess = (string) $geraetId;
$jsonUrl = '/externe-geraete/json/audio-id-' . $geraetId . '.json';
?>
<!DOCTYPE html>
<html>
<head>
<title>Remote Audioplayer</title>
<meta name="robots" content="noindex">
<script src="/intern/js/jquery/jquery-3.7.1.min.js"></script>
<script src="/intern/js/custom-msg-display.js"></script>
<link rel="stylesheet" href="/intern/css/custom-msg-display.css">
<link rel="stylesheet" href="/externe-geraete/css/audio.css">
</head>
<body>
<section>
<div class="header">
<h1 id="title">Audioplayer</h1>
<p id="subtitle"><?= $disciplines_indexed[$geraetId] ?></p>
</div>
<button class="startButton">
Audioplayer starten
</button>
<div class="currentyPlaying hidden">
Aktuell laufendes Audio:
<div class="subDivCurrentyPlaying">
<span>Dateiname: <span class="spanFilename"></span></span>
<span class="spanPersonname">Name der Person:
<span class="spanPersonnameName"></span>,
<span class="spanPersonnameVorname"></span>
</span>
</div>
<div class="progressDiv">
<div id="progressContainer">
<div id="progressBar"></div>
</div>
<span class="progressText"><span id="currentText">0:00</span> / <span id="durationText">0:00</span></span>
</div>
</div>
<div class="content">
Dies ist der Live Audioplayer. Audio kann über die Kampfrichteransicht gestartet werden.
</div>
</section>
<audio id="peep" preload="auto"></audio>
<audio id="musicPlayer" preload="auto"></audio>
<script>
const WSaccesstype = "<?= $WSaccesstype ?>";
const WSaccess = "<?= $WSaccess ?>";
const csrf_token = "<?= $csrf_token ?>";
const WSaccessPermission = "<?= $WSaccessPermission ?>"
const jsonUrl = "<?php echo $jsonUrl; ?>";
let ws;
let firstConnect = true;
const RETRY_DELAY = 2000;
const urlAjaxNewWSToken = '/intern/scripts/ajax-create-ws-token.php';
async function fetchNewWSToken(accesstype, access, accessPermission) {
try {
const response = await fetch(urlAjaxNewWSToken, {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
csrf_token,
accesstype,
access,
accessPermission
})
});
if (!response.ok) return null;
const data = await response.json();
return data.success ? data.token : null;
} catch (error) {
console.error("Token fetch failed:", error);
return null;
}
}
async function startWebSocket() {
console.log("Attempting WebSocket connection...");
let token;
if (firstConnect) {
token = '<?= generateWSReadToken($WSaccesstype, $WSaccess) ?>';
} else {
token = await fetchNewWSToken(WSaccesstype, WSaccess, WSaccessPermission);
}
if (!token) {
console.error("No valid token available. Retrying...");
scheduleRetry();
return;
}
try {
ws = new WebSocket(`wss://${window.location.hostname}/ws/?access=token&token=${token}`);
} catch (err) {
console.error("Malformed WebSocket URL", err);
scheduleRetry();
return;
}
ws.onopen = () => {
console.log("WebSocket connected!");
if (!firstConnect) {
displayMsg(1, "Live Syncronisation wieder verfügbar");
}
firstConnect = true;
};
ws.onerror = (event) => {
console.error("WebSocket error observed.");
};
ws.onclose = (event) => {
displayMsg(0, "Live Syncronisation verloren");
firstConnect = false;
scheduleRetry();
};
}
function scheduleRetry() {
console.log(`Retrying in ${RETRY_DELAY}ms...`);
setTimeout(startWebSocket, RETRY_DELAY);
}
startWebSocket();
const spanFilename = $('.spanFilename');
const spanPersonname = $('.spanPersonname');
const spanPersonnameName = $('.spanPersonnameName');
const spanPersonnameVorname = $('.spanPersonnameVorname');
const currentyPlaying = $('.currentyPlaying');
const $progressBar = $('#progressBar');
const $progressContainer = $('#progressContainer');
const peep = document.getElementById('peep');
const music = document.getElementById('musicPlayer');
const $audio = $('#musicPlayer');
let lastMusicUrl = null;
let pollingStarted = false; // ensure we start polling only once
async function fetchAndHandleMusic() {
try {
const response = await fetch(jsonUrl + '?t=' + Date.now(), { cache: 'no-store' });
const data = await response.json();
if (!data.audio_path || data.audio_path === 'nan' || data.start == false) {
if (!music.paused) {
music.pause();
music.currentTime = 0;
}
if (!peep.paused) {
peep.pause();
peep.currentTime = 0;
}
lastMusicUrl = null;
return;
}
peep.src = '/files/music/piep.mp3';
music.src = data.audio_path;
music.currentTime = 0;
peep.play().then(() => {
setTimeout(() => {
music.play().catch(err => console.log('Music play error:', err));
}, 2000);
}).catch(err => console.log('Peep play error:', err));
spanFilename.text(data.audio_name ?? '');
spanPersonnameName.text(data.person.name ?? '');
spanPersonnameVorname.text(data.person.vorname ?? '');
} catch (err) {
console.error('Error fetching JSON:', err);
}
}
function formatTime(seconds) {
if (isNaN(seconds)) return "0:00";
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return mins + ":" + (secs < 10 ? '0' : '') + secs;
}
const audioDOM = $audio[0];
$audio.on('timeupdate', function() {
if (audioDOM.duration) {
const percentage = (audioDOM.currentTime / audioDOM.duration) * 100;
$progressBar.css('width', percentage + '%');
$('#currentText').text(formatTime(audioDOM.currentTime));
}
});
$audio.on('loadedmetadata', function() {
$('#durationText').text(formatTime(audioDOM.duration));
});
let isActive = false;
$('.startButton').on('click', function() {
isActive = !isActive;
if (isActive) {
$(this).text('Audioplayer stoppen');
} else {
$(this).text('Audioplayer starten');
currentyPlaying.addClass('hidden');
if (!music.paused) {
music.pause();
music.currentTime = 0;
}
if (!peep.paused) {
peep.pause();
peep.currentTime = 0;
}
}
$('section').toggleClass('playerActive', isActive);
if (!pollingStarted) {
pollingStarted = true;
ws.addEventListener("message", () => {
if (isActive) {
fetchAndHandleMusic();
currentyPlaying.removeClass('hidden');
}
});
}
});
</script>
</body>
</html>