add livestream check
This commit is contained in:
parent
4bb0c2966a
commit
032acb7664
26
app.py
26
app.py
@ -27,6 +27,7 @@ import base64
|
||||
import json
|
||||
import io
|
||||
import search
|
||||
import urllib.request
|
||||
import auth
|
||||
import analytics as a
|
||||
import folder_secret_config_editor as fsce
|
||||
@ -461,6 +462,30 @@ def create_calendar_entry():
|
||||
'details': details
|
||||
}), 201
|
||||
|
||||
@app.route('/api/livestream/status', methods=['GET'])
|
||||
@auth.require_secret
|
||||
def livestream_status():
|
||||
status_url = auth.return_app_config().get('LIVESTREAM_STATUS_URL')
|
||||
result = {"audio_live": False, "live": False}
|
||||
if not status_url:
|
||||
reply = jsonify(result)
|
||||
reply.headers['Cache-Control'] = 'no-store'
|
||||
return reply
|
||||
try:
|
||||
with urllib.request.urlopen(status_url, timeout=5) as response:
|
||||
if response.status != 200:
|
||||
raise ValueError(f"Status endpoint returned {response.status}")
|
||||
payload = response.read()
|
||||
parsed = json.loads(payload.decode('utf-8'))
|
||||
result["audio_live"] = bool(parsed.get("audio_live", False))
|
||||
result["live"] = bool(parsed.get("live", False))
|
||||
except Exception as err:
|
||||
app.logger.warning("Livestream status proxy failed: %s", err)
|
||||
|
||||
reply = jsonify(result)
|
||||
reply.headers['Cache-Control'] = 'no-store'
|
||||
return reply
|
||||
|
||||
# Grab the HOST_RULE environment variable
|
||||
host_rule = os.getenv("HOST_RULE", "")
|
||||
# Use a regex to extract domain names between backticks in patterns like Host(`something`)
|
||||
@ -1289,6 +1314,7 @@ def index(path):
|
||||
features=app_config.get('FEATURES', None),
|
||||
og_title=og_title,
|
||||
og_description=og_description,
|
||||
livestream_url=app_config.get('LIVESTREAM_URL') or '',
|
||||
admin_enabled=auth.is_admin()
|
||||
)
|
||||
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
"ADMIN_KEY": "THIS_IS_USED_TO_AUTHENTICATE_ADMIN",
|
||||
"TITLE_SHORT": "Gottesdienste",
|
||||
"TITLE_LONG": "Gottesdienste App",
|
||||
"LIVESTREAM_URL": "https://streaming.bethaus-speyer.de",
|
||||
"LIVESTREAM_STATUS_URL": "https://streaming.bethaus-speyer.de/status",
|
||||
"BASE_DIR": "/mnt",
|
||||
"filecache_size_limit_audio": 16,
|
||||
"filecache_size_limit_image": 16,
|
||||
|
||||
@ -128,6 +128,46 @@ main > * {
|
||||
margin: 12px 0;
|
||||
}
|
||||
|
||||
.livestream-alert {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.livestream-button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 8px 14px;
|
||||
border-radius: 999px;
|
||||
background: rgba(0, 0, 0, 0.12);
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
color: inherit;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
transition: background-color 0.2s ease, transform 0.2s ease, box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
.livestream-button:hover,
|
||||
.livestream-button:focus-visible {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
box-shadow: 0 6px 14px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.livestream-button:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
.livestream-alert {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Search view container (custom element) */
|
||||
search {
|
||||
display: block;
|
||||
|
||||
@ -796,9 +796,60 @@ function initTranscriptModal() {
|
||||
modal.dataset.bound = '1';
|
||||
}
|
||||
|
||||
const LIVESTREAM_STATUS_URL = '/api/livestream/status';
|
||||
const LIVESTREAM_POLL_INTERVAL_MS = 60000;
|
||||
let livestreamStatusIntervalId = null;
|
||||
let livestreamStatusErrorLogged = false;
|
||||
|
||||
function setLivestreamAlertVisible(isVisible) {
|
||||
const alertEl = document.getElementById('livestream-alert');
|
||||
if (!alertEl) return;
|
||||
alertEl.classList.toggle('d-none', !isVisible);
|
||||
alertEl.setAttribute('aria-hidden', String(!isVisible));
|
||||
}
|
||||
|
||||
async function checkLivestreamStatus() {
|
||||
const alertEl = document.getElementById('livestream-alert');
|
||||
if (!alertEl) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(LIVESTREAM_STATUS_URL, {
|
||||
cache: 'no-store',
|
||||
credentials: 'same-origin',
|
||||
headers: { 'Accept': 'application/json' }
|
||||
});
|
||||
if (!response.ok) throw new Error(`Livestream status request failed (${response.status})`);
|
||||
const contentType = response.headers.get('content-type') || '';
|
||||
if (!contentType.includes('application/json')) {
|
||||
const text = await response.text();
|
||||
throw new Error(`Livestream status returned non-JSON: ${text.slice(0, 120)}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
const isLive = Boolean(data && (data.live || data.audio_live));
|
||||
setLivestreamAlertVisible(isLive);
|
||||
} catch (err) {
|
||||
if (!livestreamStatusErrorLogged) {
|
||||
console.warn('Livestream status check failed', err);
|
||||
livestreamStatusErrorLogged = true;
|
||||
}
|
||||
setLivestreamAlertVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
function initLivestreamStatus() {
|
||||
const alertEl = document.getElementById('livestream-alert');
|
||||
if (!alertEl) return;
|
||||
|
||||
checkLivestreamStatus();
|
||||
if (!livestreamStatusIntervalId) {
|
||||
livestreamStatusIntervalId = setInterval(checkLivestreamStatus, LIVESTREAM_POLL_INTERVAL_MS);
|
||||
}
|
||||
}
|
||||
|
||||
function initAppPage() {
|
||||
attachEventListeners();
|
||||
initTranscriptModal();
|
||||
initLivestreamStatus();
|
||||
if (typeof window.initSearch === 'function') window.initSearch();
|
||||
if (typeof window.initMessages === 'function') window.initMessages();
|
||||
if (typeof window.initGallery === 'function') window.initGallery();
|
||||
|
||||
@ -21,6 +21,13 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container">
|
||||
<div id="livestream-alert" class="alert alert-warning livestream-alert d-none" role="status" aria-live="polite">
|
||||
<span>Zurzeit findet ein Livestream statt.</span>
|
||||
<a class="alert-link livestream-button" id="livestream-link" href="{{ livestream_url }}" target="_blank" rel="noopener">Zum Livestream wechseln</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tab Navigation -->
|
||||
{% if features %}
|
||||
<nav class="main-tabs">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user