- YouTube antwortet auf Kanal-Feeds derzeit bei etwa zwei von drei Abrufen grundlos mit 404 (Kanäle zeigten „lädt nicht: HTTP 404“): ein YouTube-Feed wird bis zu 12-mal im Abstand von 0,25 s gefragt. Tests dazu. - Erscheinungsbild „Automatisch“: in der Android-App folgt die WebView nicht dem System, sondern dem (dunklen) App-Theme – die Seite fragt dort DioraNative.systemScheme() und hört __dioraSystemScheme bei einem Wechsel. sw.js: diora-v129. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
112 lines
5.1 KiB
HTML
112 lines
5.1 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="de">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="theme-color" content="#000000">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
|
<meta name="apple-mobile-web-app-title" content="diora">
|
|
<meta name="description" content="Bücher, Podcasts und Radio">
|
|
{% if user.is_authenticated %}<meta name="username" content="{{ user.username }}">{% endif %}
|
|
<link rel="manifest" href="/static/manifest.json">
|
|
<link rel="apple-touch-icon" href="/static/icon-192.png">
|
|
<script>
|
|
// Light and dark (docs/theme.md): the choice is "dark", "light" or "auto" (as the
|
|
// system says). Set before anything paints; every page has it, app.js or not.
|
|
// Plain ES5: old e-reader WebViews run this too.
|
|
(function () {
|
|
var KEY = 'diora_theme';
|
|
var LABELS = {dark: 'Dunkel', light: 'Hell', auto: 'Automatisch'};
|
|
var mq = window.matchMedia ? window.matchMedia('(prefers-color-scheme: light)') : null;
|
|
// In the Android app the WebView's media query follows the app's own theme, not the
|
|
// system: the app tells what the system is set to (DioraNative.systemScheme, and
|
|
// __dioraSystemScheme when it switches).
|
|
var nat = window.DioraNative && typeof window.DioraNative.systemScheme === 'function' ? window.DioraNative : null;
|
|
var sys = null;
|
|
function systemLight() {
|
|
if (nat) { if (sys === null) { try { sys = nat.systemScheme(); } catch (e) { sys = 'dark'; } } return sys === 'light'; }
|
|
return !!(mq && mq.matches);
|
|
}
|
|
function choice() {
|
|
var v = null;
|
|
try { v = localStorage.getItem(KEY); } catch (e) {}
|
|
return v === 'light' || v === 'auto' ? v : 'dark';
|
|
}
|
|
function scheme() {
|
|
var c = choice();
|
|
return c === 'light' || (c === 'auto' && systemLight()) ? 'light' : 'dark';
|
|
}
|
|
function apply() {
|
|
var s = scheme();
|
|
document.documentElement.setAttribute('data-theme', s);
|
|
var meta = document.querySelector('meta[name="theme-color"]');
|
|
if (meta) meta.setAttribute('content', s === 'light' ? '#f6f5f1' : '#000000');
|
|
var b = document.getElementById('theme-toggle');
|
|
if (b) {
|
|
var c = choice();
|
|
b.textContent = c === 'light' ? '\u2600' : c === 'auto' ? '\u25D0' : '\u263E';
|
|
b.title = 'Erscheinungsbild: ' + LABELS[c];
|
|
}
|
|
try { window.dispatchEvent(new CustomEvent('diora-theme', {detail: s})); } catch (e) {}
|
|
}
|
|
window.__dioraTheme = choice;
|
|
window.__dioraSetTheme = function (c) {
|
|
try { localStorage.setItem(KEY, LABELS[c] ? c : 'dark'); } catch (e) {}
|
|
apply();
|
|
};
|
|
window.cycleTheme = function () {
|
|
var order = ['dark', 'light', 'auto'];
|
|
window.__dioraSetTheme(order[(order.indexOf(choice()) + 1) % order.length]);
|
|
};
|
|
if (mq && mq.addEventListener) mq.addEventListener('change', function () { if (choice() === 'auto') apply(); });
|
|
window.__dioraSystemScheme = function (s) { sys = s; if (choice() === 'auto') apply(); };
|
|
document.addEventListener('DOMContentLoaded', apply);
|
|
document.documentElement.setAttribute('data-theme', scheme());
|
|
})();
|
|
</script>
|
|
<link rel="stylesheet" href="/static/css/app.css">
|
|
<title>{% block title %}diora{% endblock %}</title>
|
|
<script>const DIORA_CONFIG = { ebookMaxBytes: {{ EBOOK_MAX_BYTES }}, bgMaxBytes: {{ BG_MAX_BYTES }}, podcastInboxPageSize: {{ PODCAST_INBOX_PAGE_SIZE }} };</script>
|
|
{% if encrypted_bg_json %}
|
|
<script>const ENCRYPTED_BG = {{ encrypted_bg_json|safe }};</script>
|
|
{% endif %}
|
|
</head>
|
|
<body>
|
|
<nav class="navbar">
|
|
<a href="/" class="navbar-brand">diora</a>
|
|
<div class="navbar-links">
|
|
<button class="btn-icon theme-toggle" id="theme-toggle" onclick="cycleTheme()" title="Erscheinungsbild">☾</button>
|
|
<button class="btn-icon contrast-toggle" id="contrast-toggle" onclick="toggleContrast()" title="Kontrast zum Hintergrundbild" hidden>◑</button>
|
|
{% if user.is_authenticated %}
|
|
<span class="navbar-user">{{ user.username }}</span>
|
|
<a href="{% url 'settings' %}">Einstellungen</a>
|
|
<form method="post" action="{% url 'logout' %}" class="inline-form">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn-link">Abmelden</button>
|
|
</form>
|
|
{% else %}
|
|
<a href="{% url 'login' %}">Anmelden</a>
|
|
<a href="{% url 'register' %}">Registrieren</a>
|
|
{% endif %}
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="main-content">
|
|
{% if messages %}
|
|
<div class="messages">
|
|
{% for message in messages %}
|
|
<div class="message message-{{ message.tags }}">{{ message }}</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
{% if BUILD_TIME %}<span class="build-time">{{ BUILD_TIME|slice:":16"|cut:"T" }}</span>{% endif %}
|
|
<script src="/static/js/jszip.min.js"></script>
|
|
<script src="/static/js/pdf.min.js"></script>
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html>
|