diff --git a/docker-exports/videoconverter-4.0.1.tar b/docker-exports/videoconverter-4.0.1.tar deleted file mode 100644 index 9ce2121..0000000 Binary files a/docker-exports/videoconverter-4.0.1.tar and /dev/null differ diff --git a/tizen-app/VideoKonverter.wgt b/tizen-app/VideoKonverter.wgt index 0bcd1c3..2ea5e57 100644 Binary files a/tizen-app/VideoKonverter.wgt and b/tizen-app/VideoKonverter.wgt differ diff --git a/tizen-app/config.xml b/tizen-app/config.xml index c90f4eb..866ba68 100644 --- a/tizen-app/config.xml +++ b/tizen-app/config.xml @@ -1,6 +1,6 @@ + id="http://data-it-solution.de/videokonverter" version="5.5.0" viewmodes="maximized"> VideoKonverter VideoKonverter TV-App - Serien und Filme streamen mit AVPlay Direct-Play @@ -24,6 +24,9 @@ + + * + diff --git a/tizen-app/index.html b/tizen-app/index.html index ecbea1d..c38e867 100644 --- a/tizen-app/index.html +++ b/tizen-app/index.html @@ -32,19 +32,21 @@ } /* Setup-Bildschirm */ .setup { - display: flex; - align-items: center; - justify-content: center; - height: 100vh; position: absolute; top: 0; left: 0; width: 100%; + height: 100%; z-index: 100; + background: #0f0f0f; } .setup-inner { text-align: center; max-width: 600px; + margin: 0 auto; padding: 2rem; + position: relative; + top: 50%; + transform: translateY(-50%); } .setup h1 { font-size: 2rem; margin-bottom: 1rem; color: #64b5f6; } .setup p { font-size: 1.2rem; color: #aaa; margin-bottom: 2rem; } @@ -60,6 +62,33 @@ } .setup button:focus { outline: 3px solid #64b5f6; outline-offset: 4px; } .hint { margin-top: 1.5rem; font-size: 0.9rem; color: #666; } + .error-msg { color: #ef5350; font-size: 1.1rem; margin-top: 0.5rem; margin-bottom: 1rem; display: none; } + /* Verbindungs-Overlay */ + #connecting-overlay { + position: fixed; top: 0; left: 0; width: 100%; height: 100%; + background: #0f0f0f; z-index: 50; + display: none; align-items: center; justify-content: center; + flex-direction: column; + } + #connecting-overlay .spinner { + width: 48px; height: 48px; border: 4px solid #333; + border-top-color: #64b5f6; border-radius: 50%; + animation: spin 0.8s linear infinite; margin-bottom: 1rem; + } + @keyframes spin { to { transform: rotate(360deg); } } + #connecting-overlay .msg { color: #aaa; font-size: 1.2rem; } + #connecting-overlay .btn-cancel { + margin-top: 2rem; padding: 0.8rem 2rem; font-size: 1rem; + background: #c62828; color: #fff; border: none; border-radius: 8px; cursor: pointer; + } + /* Debug-Panel: Gruene Taste (Fernbedienung) toggled Sichtbarkeit */ + #dbg { + position: fixed; bottom: 0; left: 0; right: 0; z-index: 99999; + background: rgba(0,0,0,0.92); color: #0f0; font-family: monospace; + font-size: 13px; padding: 6px 10px; max-height: 40vh; overflow-y: auto; + border-top: 2px solid #0a0; display: none; + } + #dbg .e { color: #f44; } #dbg .w { color: #ff0; } #dbg .i { color: #0f0; } @@ -70,12 +99,24 @@

Server-Adresse eingeben:

-
- -

Die Adresse wird gespeichert und beim naechsten Start automatisch geladen.

+

+ +

Nur IP:Port eingeben (z.B. 192.168.155.12:8080).
+ http:// und /tv/ werden automatisch ergaenzt.

+

v5.5.0 | Gruene Taste = Debug-Log

+ +
+
+
Verbinde mit Server...
+ +
+ + +
+ @@ -86,10 +127,82 @@ diff --git a/video-konverter/app/routes/tv_api.py b/video-konverter/app/routes/tv_api.py index 81f2a1a..c97bd92 100644 --- a/video-konverter/app/routes/tv_api.py +++ b/video-konverter/app/routes/tv_api.py @@ -77,12 +77,17 @@ def setup_tv_routes(app: web.Application, config: Config, # --- Auth-Hilfsfunktionen --- def _cookie_params(request: web.Request) -> dict: - """SameSite-Parameter je nach Protokoll: None+Secure bei HTTPS, Lax bei HTTP. - Browser verwerfen SameSite=None ohne Secure-Flag stillschweigend.""" + """SameSite-Parameter je nach Protokoll und Client. + Tizen-WGT-App: iframe-Context -> SameSite weglassen (Lax blockiert Cookies in iframes). + HTTPS: SameSite=None+Secure. HTTP normal: Lax.""" + ua = request.headers.get("User-Agent", "") is_https = (request.secure or request.headers.get("X-Forwarded-Proto") == "https") if is_https: return {"samesite": "None", "secure": True} + # Tizen-App laeuft im iframe -> SameSite weglassen damit Cookie gesetzt wird + if "Tizen" in ua: + return {} return {"samesite": "Lax"} async def get_tv_user(request: web.Request) -> dict | None: @@ -1746,6 +1751,56 @@ def setup_tv_routes(app: web.Application, config: Config, await hls_manager.destroy_session(sid) return web.json_response({"success": True}) + # --- Tizen Debug-Log --- + + async def post_tizen_log(request): + """Empfaengt Log-Eintraege von der Tizen WGT-App und speichert in DB""" + try: + data = await request.json() + entries = data.get("entries", []) + ua = data.get("userAgent", "")[:500] + if not entries: + return web.json_response({"ok": True, "count": 0}) + pool = library_service._db_pool + async with pool.acquire() as conn: + async with conn.cursor() as cur: + for e in entries[:50]: # Max 50 pro Request + await cur.execute( + "INSERT INTO tizen_logs (level, message, user_agent, client_ts) " + "VALUES (%s, %s, %s, %s)", + (e.get("l", "I"), e.get("m", "")[:2000], + ua, e.get("t", "")) + ) + await conn.commit() + return web.json_response({"ok": True, "count": len(entries)}) + except Exception as ex: + logging.warning(f"Tizen-Log Fehler: {ex}") + return web.json_response({"ok": False, "error": str(ex)}, status=400) + + async def get_tizen_log(request): + """Gibt die letzten Tizen-Logs zurueck (fuer Debugging)""" + limit = int(request.query.get("limit", "100")) + level = request.query.get("level", "") + pool = library_service._db_pool + async with pool.acquire() as conn: + async with conn.cursor(aiomysql.DictCursor) as cur: + if level: + await cur.execute( + "SELECT * FROM tizen_logs WHERE level = %s " + "ORDER BY id DESC LIMIT %s", (level, limit)) + else: + await cur.execute( + "SELECT * FROM tizen_logs ORDER BY id DESC LIMIT %s", + (limit,)) + rows = await cur.fetchall() + # Chronologisch (aelteste zuerst) + rows.reverse() + # Timestamps serialisierbar machen + for r in rows: + if r.get("created_at"): + r["created_at"] = str(r["created_at"]) + return web.json_response(rows) + # --- Routes registrieren --- # TV-Seiten (mit Auth via Decorator) @@ -1807,3 +1862,7 @@ def setup_tv_routes(app: web.Application, config: Config, app.router.add_delete("/api/tv/users/{id}", delete_user) app.router.add_get("/api/tv/hls-sessions", get_hls_sessions) app.router.add_delete("/api/tv/hls-sessions/{sid}", delete_hls_session_admin) + + # Tizen Debug-Log API (kein Auth, Daten von WGT-App) + app.router.add_post("/api/tizen-log", post_tizen_log) + app.router.add_get("/api/tizen-log", get_tizen_log) diff --git a/video-konverter/app/static/tv/sw.js b/video-konverter/app/static/tv/sw.js index 0204d0b..3a54314 100644 --- a/video-konverter/app/static/tv/sw.js +++ b/video-konverter/app/static/tv/sw.js @@ -4,7 +4,7 @@ * Kein Offline-Caching noetig (Streaming braucht Netzwerk) */ -const CACHE_NAME = "vk-tv-v14"; +const CACHE_NAME = "vk-tv-v15"; const STATIC_ASSETS = [ "/static/tv/css/tv.css", "/static/tv/js/tv.js", diff --git a/video-konverter/app/templates/tv/base.html b/video-konverter/app/templates/tv/base.html index 12d0882..c3c4242 100644 --- a/video-konverter/app/templates/tv/base.html +++ b/video-konverter/app/templates/tv/base.html @@ -48,6 +48,11 @@ {% block scripts %}{% endblock %}