docker.videokonverter/video-konverter/app/templates/tv/login.html
data 00d8f6b982 feat: VideoKonverter v5.5 - Tizen Remote-Logging, Login D-Pad, Cookie-Fix
Tizen-App v5.5.0:
- Remote-Logging: Console-Override + XHR an /api/tizen-log alle 3s
- Debug-Panel: Gruene Taste toggled scrollbares Log-Panel (unten)
- window.onerror Handler fuer uncaught Errors
- Alle v5.4.2 Features erhalten (Connecting-Overlay, Timeout, IME-Fixes)

Server (tv_api.py):
- POST/GET /api/tizen-log Endpunkte (DB-Tabelle tizen_logs)
- Cookie SameSite-Fix: Tizen iframe bekommt kein SameSite (Lax blockiert)

Login (login.html):
- D-Pad Navigation per postMessage (vknative_keyevent)
- ArrowUp/Down zwischen Feldern, Enter auf Button

Sonstiges:
- base.html: vk_app_loaded postMessage Signal
- sw.js: Cache v14 -> v15
- Altes Docker-Export entfernt

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 20:05:22 +01:00

111 lines
4.6 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#0f0f0f">
<link rel="stylesheet" href="/static/tv/css/tv.css?v={{ v }}">
<title>Login - VideoKonverter TV</title>
</head>
<body class="login-body">
<!-- Lade-Spinner (verhindert Flash des Login-Formulars) -->
<div class="login-loader" id="login-loader">
<div class="login-spinner"></div>
</div>
<div class="login-container" id="login-container" style="display:none">
<div class="login-card">
<h1 class="login-title">VideoKonverter</h1>
<p class="login-subtitle">TV-Streaming</p>
{% if error %}
<div class="login-error">{{ error }}</div>
{% endif %}
<form method="POST" action="/tv/login" class="login-form">
<div class="login-field">
<label for="username">Benutzername</label>
<input type="text" id="username" name="username"
autocomplete="username"
data-focusable required>
</div>
<div class="login-field">
<label for="password">Passwort</label>
<input type="password" id="password" name="password"
autocomplete="current-password"
data-focusable required>
</div>
<div class="login-field login-remember">
<label class="settings-check">
<input type="checkbox" name="remember" data-focusable>
Angemeldet bleiben
</label>
</div>
<button type="submit" class="login-btn" data-focusable>
Anmelden
</button>
</form>
</div>
</div>
<script>
// Tizen iframe: Parent signalisieren dass die App geladen hat
if (window.parent !== window) {
try { window.parent.postMessage({type: "vk_app_loaded"}, "*"); } catch(e) {}
}
// === D-Pad Navigation fuer Login-Formular (Tizen/Samsung Fernbedienung) ===
(function() {
// postMessage-Events vom Tizen-Parent empfangen und als KeyboardEvent dispatchen
window.addEventListener("message", function(evt) {
var d = evt.data;
if (!d || d.type !== "vknative_keyevent" || !d.keyCode) return;
var keyMap = {13:"Enter",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",27:"Escape",8:"Backspace",10009:"Escape"};
var ke = new KeyboardEvent("keydown", {keyCode:d.keyCode, which:d.keyCode, key:keyMap[d.keyCode]||"", bubbles:true});
document.dispatchEvent(ke);
});
// Focusable Elemente sammeln und D-Pad-Navigation
function getFocusables() {
return Array.prototype.slice.call(document.querySelectorAll("[data-focusable]"));
}
document.addEventListener("keydown", function(e) {
var els = getFocusables();
if (!els.length) return;
var idx = els.indexOf(document.activeElement);
if (e.key === "ArrowDown" || e.keyCode === 40) {
e.preventDefault();
els[idx < els.length - 1 ? idx + 1 : 0].focus();
} else if (e.key === "ArrowUp" || e.keyCode === 38) {
e.preventDefault();
els[idx > 0 ? idx - 1 : els.length - 1].focus();
} else if ((e.key === "Enter" || e.keyCode === 13) && document.activeElement.tagName === "BUTTON") {
document.activeElement.click();
}
});
})();
// Pruefen ob Browser Felder vorausgefuellt hat -> automatisch absenden
var _autoAttempts = 0;
var _autoInterval = setInterval(function() {
_autoAttempts++;
var u = document.getElementById('username');
var p = document.getElementById('password');
if (u && p && u.value && p.value) {
clearInterval(_autoInterval);
document.querySelector('.login-form').submit();
return;
}
if (_autoAttempts >= 5) {
clearInterval(_autoInterval);
// Kein Auto-Fill -> Formular anzeigen
document.getElementById('login-loader').style.display = 'none';
var container = document.getElementById('login-container');
container.style.display = '';
container.style.animation = 'fadeIn 0.3s ease';
if (u) u.focus();
}
}, 200);
</script>
</body>
</html>