PROBLEME BEHOBEN: - Schwarzes Bild beim Video-Abspielen (z-index & iframe-Overlap) - Login-Cookie wurde nicht gesetzt (Third-Party-Cookie-Blocking) ÄNDERUNGEN: Tizen-App (tizen-app/index.html): - z-index AVPlay von 0 auf 10 erhöht (über iframe) - iframe wird beim AVPlay-Start ausgeblendet (opacity: 0, pointerEvents: none) - iframe wird beim AVPlay-Stop wieder eingeblendet - Fix: <object id="avplayer"> nur im Parent, NICHT im iframe Player-Template (video-konverter/app/templates/tv/player.html): - <object id="avplayer"> entfernt (existiert nur im Parent-Frame) - AVPlay läuft ausschließlich im Tizen-App Parent-Frame Cookie-Fix (video-konverter/app/routes/tv_api.py): - SameSite=Lax → SameSite=None (4 Stellen) - Ermöglicht Session-Cookies im Cross-Origin-iframe - Login funktioniert jetzt in Tizen-App (tizen:// → http://) Neue Features: - VKNative Bridge (vknative-bridge.js): postMessage-Kommunikation iframe ↔ Parent - AVPlay Bridge (avplay-bridge.js): Legacy Direct-Play Support - Android-App Scaffolding (android-app/) TESTERGEBNIS: - ✅ Login erfolgreich (SameSite=None Cookie) - ✅ AVPlay Direct-Play funktioniert (samsung-agent/1.1) - ✅ Bildqualität gut (Hardware-Decoding) - ✅ Keine Stream-Unterbrechungen - ✅ Watch-Progress-Tracking funktioniert Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
109 lines
5.6 KiB
HTML
109 lines
5.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="#000000">
|
|
<link rel="stylesheet" href="/static/tv/css/tv.css?v={{ v }}">
|
|
<title>{{ title }} - VideoKonverter TV</title>
|
|
</head>
|
|
<body class="player-body">
|
|
<div class="player-wrapper" id="player-wrapper">
|
|
<!-- Header (ausblendbar) -->
|
|
<div class="player-header" id="player-header">
|
|
<a href="javascript:history.back()" class="player-back" data-focusable>❮ {{ t('player.back') }}</a>
|
|
<span class="player-title">{{ title }}</span>
|
|
</div>
|
|
|
|
<!-- Loading-Spinner (sichtbar bis Stream bereit) -->
|
|
<div class="player-loading" id="player-loading">
|
|
<div class="player-loading-spinner"></div>
|
|
<p class="player-loading-text">Stream wird geladen...</p>
|
|
</div>
|
|
|
|
<!-- Video (HTML5 fuer HLS, versteckt bei AVPlay Direct-Play) -->
|
|
<video id="player-video" autoplay playsinline></video>
|
|
|
|
<!-- Controls (ausblendbar) -->
|
|
<div class="player-controls" id="player-controls">
|
|
<div class="player-progress" id="player-progress">
|
|
<div class="player-progress-bar" id="player-progress-bar"></div>
|
|
</div>
|
|
<div class="player-buttons">
|
|
<button class="player-btn" id="btn-play" data-focusable>▶</button>
|
|
<span class="player-time" id="player-time">0:00 / 0:00</span>
|
|
<span class="player-spacer"></span>
|
|
<button class="player-btn" id="btn-audio" data-focusable title="{{ t('player.audio') }}">
|
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M15.5 8.5a5 5 0 010 7"/></svg>
|
|
</button>
|
|
<button class="player-btn" id="btn-subs" data-focusable title="{{ t('player.subtitles') }}">
|
|
<span class="player-btn-badge">CC</span>
|
|
</button>
|
|
<button class="player-btn" id="btn-quality" data-focusable title="{{ t('player.quality') }}">
|
|
<span class="player-btn-badge" id="quality-badge">HD</span>
|
|
</button>
|
|
<button class="player-btn" id="btn-settings" data-focusable title="{{ t('player.settings') }}">⚙</button>
|
|
{% if next_video %}
|
|
<button class="player-btn" id="btn-next" data-focusable title="{{ t('player.next_episode') }}">⏭</button>
|
|
{% endif %}
|
|
<button class="player-btn" id="btn-fullscreen" data-focusable>⛶</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Kompaktes Popup-Menue (ersetzt das grosse Overlay-Panel) -->
|
|
<div class="player-popup" id="player-popup" style="display:none"></div>
|
|
|
|
<!-- Naechste Episode Overlay -->
|
|
{% if next_video %}
|
|
<div class="player-next-overlay" id="next-overlay" style="display:none">
|
|
<div class="player-next-card">
|
|
<p class="player-next-title" id="next-title">{{ t('player.next_episode') }}</p>
|
|
<p class="player-next-name">{{ next_title }}</p>
|
|
<p class="player-next-countdown" id="next-countdown"></p>
|
|
<div class="player-next-buttons">
|
|
<button class="tv-play-btn" id="btn-next-play" data-focusable>{{ t('player.skip') }}</button>
|
|
<button class="player-btn-cancel" id="btn-next-cancel" data-focusable>{{ t('player.cancel') }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Schaust du noch? Overlay -->
|
|
<div class="player-still-watching" id="still-watching-overlay" style="display:none">
|
|
<div class="player-next-card">
|
|
<p class="player-next-title">{{ t('player.still_watching') }}</p>
|
|
<div class="player-next-buttons">
|
|
<button class="tv-play-btn" id="btn-still-yes" data-focusable>{{ t('player.continue') }}</button>
|
|
<button class="player-btn-cancel" id="btn-still-no" data-focusable>{{ t('player.stop') }}</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- VKNative Bridge: Tizen AVPlay (auf Nicht-Tizen macht das Script nichts) -->
|
|
<!-- Android injiziert VKNative per @JavascriptInterface, Bridge erkennt das und ueberspringt -->
|
|
<script src="/static/tv/js/vknative-bridge.js?v={{ v }}"></script>
|
|
<!-- hls.js als Fallback fuer HLS-Streaming -->
|
|
<script src="/static/tv/js/lib/hls.min.js?v={{ v }}"></script>
|
|
<script src="/static/tv/js/player.js?v={{ v }}"></script>
|
|
<script>
|
|
initPlayer({
|
|
videoId: {{ video.id }},
|
|
startPos: {{ start_pos }},
|
|
duration: {{ video.duration_sec or 0 }},
|
|
{% if next_video %}
|
|
nextVideoId: {{ next_video.id }},
|
|
nextUrl: "/tv/player?v={{ next_video.id }}",
|
|
{% endif %}
|
|
autoplay: {{ 'true' if user.autoplay_enabled else 'false' }},
|
|
autoplayCountdown: {{ user.autoplay_countdown_sec or 10 }},
|
|
autoplayMax: {{ user.autoplay_max_episodes or 0 }},
|
|
preferredAudio: "{{ user.preferred_audio_lang or 'deu' }}",
|
|
preferredSub: "{{ user.preferred_subtitle_lang or '' }}",
|
|
subtitlesEnabled: {{ 'true' if user.subtitles_enabled else 'false' }},
|
|
soundMode: "{{ client_sound_mode or 'stereo' }}",
|
|
streamQuality: "{{ client_stream_quality or 'hd' }}",
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|