- TV Admin-Center (/tv-admin): HLS-Settings, Session-Monitoring, User-Verwaltung - HLS-Streaming: ffmpeg .ts-Segmente, hls.js, GPU VAAPI, SIGSTOP/SIGCONT - Startseite: Rubriken (Weiterschauen, Neu, Serien, Filme, Schon gesehen) - User-Settings: Startseiten-Rubriken konfigurierbar, Watch-Threshold - UI: Amber/Gold Accent-Farbe, Focus-Ring-Fix, Player-Buttons einheitlich - Cache-Busting: ?v= Timestamp auf allen CSS/JS Includes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
225 lines
13 KiB
HTML
225 lines
13 KiB
HTML
{% extends "tv/base.html" %}
|
|
{% block title %}{{ t('settings.title') }} - VideoKonverter TV{% endblock %}
|
|
|
|
{% block content %}
|
|
<section class="tv-section">
|
|
<h1 class="tv-page-title">{{ t('settings.title') }}</h1>
|
|
|
|
{% if request.query.get('saved') %}
|
|
<div class="tv-success-msg">{{ t('settings.saved') }}</div>
|
|
{% endif %}
|
|
{% if request.query.get('reset') %}
|
|
<div class="tv-success-msg">{{ t('status.reset_progress') }} ✓</div>
|
|
{% endif %}
|
|
|
|
<form method="post" action="/tv/settings" class="settings-form">
|
|
|
|
<!-- Profil -->
|
|
<fieldset class="settings-group">
|
|
<legend>{{ t('settings.profile') }}</legend>
|
|
<label class="settings-label">
|
|
{{ t('settings.display_name') }}
|
|
<input type="text" name="display_name" value="{{ user.display_name or '' }}"
|
|
class="settings-input" data-focusable>
|
|
</label>
|
|
<div class="settings-label">
|
|
{{ t('settings.avatar_color') }}
|
|
<input type="hidden" name="avatar_color" id="avatar-color-input"
|
|
value="{{ user.avatar_color or '#64b5f6' }}">
|
|
<div class="color-picker-grid">
|
|
{% set colors = ['#64b5f6', '#42a5f5', '#5c6bc0', '#7e57c2', '#ab47bc',
|
|
'#ec407a', '#ef5350', '#ff7043', '#ffa726', '#ffca28',
|
|
'#66bb6a', '#26a69a', '#26c6da', '#78909c', '#8d6e63'] %}
|
|
{% for c in colors %}
|
|
<button type="button" class="color-swatch {% if (user.avatar_color or '#64b5f6') == c %}active{% endif %}"
|
|
style="background:{{ c }}" data-color="{{ c }}" data-focusable
|
|
onclick="selectColor(this, '{{ c }}')"></button>
|
|
{% endfor %}
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
|
|
<!-- Sprache -->
|
|
<fieldset class="settings-group">
|
|
<legend>{{ t('settings.language') }}</legend>
|
|
<label class="settings-label">
|
|
{{ t('settings.menu_language') }}
|
|
<select name="ui_lang" class="settings-select" data-focusable>
|
|
<option value="de" {% if user.ui_lang == 'de' %}selected{% endif %}>Deutsch</option>
|
|
<option value="en" {% if user.ui_lang == 'en' %}selected{% endif %}>English</option>
|
|
</select>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.audio_language') }}
|
|
<select name="preferred_audio_lang" class="settings-select" data-focusable>
|
|
<option value="deu" {% if user.preferred_audio_lang == 'deu' %}selected{% endif %}>{{ t('lang.deu') }}</option>
|
|
<option value="eng" {% if user.preferred_audio_lang == 'eng' %}selected{% endif %}>{{ t('lang.eng') }}</option>
|
|
<option value="fra" {% if user.preferred_audio_lang == 'fra' %}selected{% endif %}>{{ t('lang.fra') }}</option>
|
|
<option value="spa" {% if user.preferred_audio_lang == 'spa' %}selected{% endif %}>{{ t('lang.spa') }}</option>
|
|
<option value="jpn" {% if user.preferred_audio_lang == 'jpn' %}selected{% endif %}>{{ t('lang.jpn') }}</option>
|
|
</select>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.subtitle_language') }}
|
|
<select name="preferred_subtitle_lang" class="settings-select" data-focusable>
|
|
<option value="" {% if not user.preferred_subtitle_lang %}selected{% endif %}>{{ t('player.subtitles_off') }}</option>
|
|
<option value="deu" {% if user.preferred_subtitle_lang == 'deu' %}selected{% endif %}>{{ t('lang.deu') }}</option>
|
|
<option value="eng" {% if user.preferred_subtitle_lang == 'eng' %}selected{% endif %}>{{ t('lang.eng') }}</option>
|
|
<option value="fra" {% if user.preferred_subtitle_lang == 'fra' %}selected{% endif %}>{{ t('lang.fra') }}</option>
|
|
</select>
|
|
</label>
|
|
<label class="settings-label settings-check">
|
|
<input type="checkbox" name="subtitles_enabled"
|
|
{% if user.subtitles_enabled %}checked{% endif %} data-focusable>
|
|
{{ t('settings.subtitles_enabled') }}
|
|
</label>
|
|
</fieldset>
|
|
|
|
<!-- Ansichten & Theme -->
|
|
<fieldset class="settings-group">
|
|
<legend>{{ t('settings.views') }}</legend>
|
|
<label class="settings-label">
|
|
{{ t('settings.theme') }}
|
|
<select name="theme" class="settings-select" data-focusable
|
|
onchange="document.documentElement.setAttribute('data-theme', this.value)">
|
|
<option value="dark" {% if user.theme == 'dark' or not user.theme %}selected{% endif %}>{{ t('settings.theme_dark') }}</option>
|
|
<option value="medium" {% if user.theme == 'medium' %}selected{% endif %}>{{ t('settings.theme_medium') }}</option>
|
|
<option value="light" {% if user.theme == 'light' %}selected{% endif %}>{{ t('settings.theme_light') }}</option>
|
|
</select>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.series_view') }}
|
|
<select name="series_view" class="settings-select" data-focusable>
|
|
<option value="grid" {% if user.series_view == 'grid' %}selected{% endif %}>{{ t('settings.view_grid') }}</option>
|
|
<option value="list" {% if user.series_view == 'list' %}selected{% endif %}>{{ t('settings.view_list') }}</option>
|
|
<option value="detail" {% if user.series_view == 'detail' %}selected{% endif %}>{{ t('settings.view_detail') }}</option>
|
|
<option value="folder" {% if user.series_view == 'folder' %}selected{% endif %}>{{ t('settings.view_folder') }}</option>
|
|
</select>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.movies_view') }}
|
|
<select name="movies_view" class="settings-select" data-focusable>
|
|
<option value="grid" {% if user.movies_view == 'grid' %}selected{% endif %}>{{ t('settings.view_grid') }}</option>
|
|
<option value="list" {% if user.movies_view == 'list' %}selected{% endif %}>{{ t('settings.view_list') }}</option>
|
|
<option value="detail" {% if user.movies_view == 'detail' %}selected{% endif %}>{{ t('settings.view_detail') }}</option>
|
|
<option value="folder" {% if user.movies_view == 'folder' %}selected{% endif %}>{{ t('settings.view_folder') }}</option>
|
|
</select>
|
|
</label>
|
|
</fieldset>
|
|
|
|
<!-- Startseite -->
|
|
<fieldset class="settings-group">
|
|
<legend>Startseite</legend>
|
|
<label class="settings-label settings-check">
|
|
<input type="checkbox" name="home_show_continue"
|
|
{% if user.home_show_continue is not defined or user.home_show_continue %}checked{% endif %} data-focusable>
|
|
"Weiterschauen" anzeigen
|
|
</label>
|
|
<label class="settings-label settings-check">
|
|
<input type="checkbox" name="home_show_new"
|
|
{% if user.home_show_new is not defined or user.home_show_new %}checked{% endif %} data-focusable>
|
|
"Neu hinzugefügt" anzeigen
|
|
</label>
|
|
<label class="settings-label settings-check">
|
|
<input type="checkbox" name="home_hide_watched"
|
|
{% if user.home_hide_watched is not defined or user.home_hide_watched %}checked{% endif %} data-focusable>
|
|
Gesehene Serien/Filme ausblenden
|
|
</label>
|
|
<label class="settings-label settings-check">
|
|
<input type="checkbox" name="home_show_watched"
|
|
{% if user.home_show_watched is not defined or user.home_show_watched %}checked{% endif %} data-focusable>
|
|
"Schon gesehen"-Rubrik anzeigen
|
|
</label>
|
|
</fieldset>
|
|
|
|
<!-- Auto-Play -->
|
|
<fieldset class="settings-group">
|
|
<legend>{{ t('settings.autoplay') }}</legend>
|
|
<label class="settings-label settings-check">
|
|
<input type="checkbox" name="autoplay_enabled"
|
|
{% if user.autoplay_enabled %}checked{% endif %} data-focusable>
|
|
{{ t('settings.autoplay_enabled') }}
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.autoplay_countdown') }}
|
|
<select name="autoplay_countdown_sec" class="settings-select" data-focusable>
|
|
{% for s in [5, 10, 15, 20, 30] %}
|
|
<option value="{{ s }}" {% if user.autoplay_countdown_sec == s %}selected{% endif %}>{{ s }} {{ t('settings.seconds') }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.autoplay_max') }}
|
|
<select name="autoplay_max_episodes" class="settings-select" data-focusable>
|
|
<option value="0" {% if user.autoplay_max_episodes == 0 %}selected{% endif %}>{{ t('settings.autoplay_max_desc') }}</option>
|
|
{% for n in [3, 5, 8, 10, 15, 20] %}
|
|
<option value="{{ n }}" {% if user.autoplay_max_episodes == n %}selected{% endif %}>{{ n }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
</fieldset>
|
|
|
|
<!-- Geraete-Einstellungen -->
|
|
{% if client %}
|
|
<fieldset class="settings-group">
|
|
<legend>{{ t('settings.client_settings') }}</legend>
|
|
<label class="settings-label">
|
|
{{ t('settings.device_name') }}
|
|
<input type="text" name="client_name" value="{{ client.name or '' }}"
|
|
placeholder="z.B. Samsung TV Wohnzimmer"
|
|
class="settings-input" data-focusable>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.sound_mode') }}
|
|
<select name="sound_mode" class="settings-select" data-focusable>
|
|
<option value="stereo" {% if client.sound_mode == 'stereo' %}selected{% endif %}>{{ t('settings.sound_stereo') }}</option>
|
|
<option value="surround" {% if client.sound_mode == 'surround' %}selected{% endif %}>{{ t('settings.sound_surround') }}</option>
|
|
<option value="original" {% if client.sound_mode == 'original' %}selected{% endif %}>{{ t('settings.sound_original') }}</option>
|
|
</select>
|
|
</label>
|
|
<label class="settings-label">
|
|
{{ t('settings.stream_quality') }}
|
|
<select name="stream_quality" class="settings-select" data-focusable>
|
|
<option value="uhd" {% if client.stream_quality == 'uhd' %}selected{% endif %}>{{ t('player.quality_uhd') }}</option>
|
|
<option value="hd" {% if client.stream_quality == 'hd' %}selected{% endif %}>{{ t('player.quality_hd') }}</option>
|
|
<option value="sd" {% if client.stream_quality == 'sd' %}selected{% endif %}>{{ t('player.quality_sd') }}</option>
|
|
<option value="low" {% if client.stream_quality == 'low' %}selected{% endif %}>{{ t('player.quality_low') }}</option>
|
|
</select>
|
|
</label>
|
|
</fieldset>
|
|
{% endif %}
|
|
|
|
<button type="submit" class="tv-play-btn settings-save" data-focusable>
|
|
{{ t('settings.save') }}
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Gefahrenzone -->
|
|
<div class="settings-danger">
|
|
<form method="post" action="/tv/settings/reset"
|
|
onsubmit="return confirm('{{ t('settings.reset_confirm') }}')">
|
|
<button type="submit" class="settings-danger-btn" data-focusable>
|
|
{{ t('settings.reset_all') }}
|
|
</button>
|
|
</form>
|
|
<form method="post" action="/tv/api/search/history"
|
|
onsubmit="fetch('/tv/api/search/history',{method:'DELETE'});this.querySelector('button').textContent='✓';return false;">
|
|
<button type="button" class="settings-danger-btn" data-focusable>
|
|
{{ t('settings.clear_search') }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</section>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
function selectColor(btn, color) {
|
|
// Aktive Markierung wechseln
|
|
document.querySelectorAll('.color-swatch').forEach(s => s.classList.remove('active'));
|
|
btn.classList.add('active');
|
|
// Hidden-Input aktualisieren
|
|
document.getElementById('avatar-color-input').value = color;
|
|
}
|
|
</script>
|
|
{% endblock %}
|