From de1c13e72f8e1d805fe0aedaf81534dfb3e7ed25 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 16 Aug 2026 10:23:00 +0200 Subject: [PATCH] fix(player,reporting): report real positions, and count an audio-only episode as watched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Returning to the foreground before the background-audio stream had started playing handed the frontend 0.0s, so the video reloaded at StartTimeTicks=0 — the episode restarted from the beginning — and the stop report that followed wrote that zero to Jellyfin as the resume point. Caught on device: locked at 18.4s, unlocked 3.5s later with ExoPlayer still IDLE. The base that turns a handoff's relative timeline into the episode's is applied once at the native tick boundary (DR-159), so before the first tick nothing has applied it. The same blind spot covers webview-rendered media, where nothing is loaded into the native backend at all and its position is a permanent 0 — which is why 14 of 14 stop reports in a 35-minute trace were zeroes, one landing 40s after the frontend had correctly reported 15:22 for the same episode. - absolute_position(): the maximum of the backend's reading, the last position webview media reported, and the handoff base. Exact rather than heuristic — at most one term is ever meaningful, and the base is a floor the stream cannot physically be behind. duration() gains the same fallback. - Withhold zero-position stop reports. A zero is never information, and Jellyfin stores the reported position as the resume point, so sending one only ever destroys a real one. - Report progress from the controller's own position ticks, through the 30s throttler it already shared with the native audio path. /Sessions/Playing/Progress was previously requested zero times in 35 minutes. - Report a finished audio-only episode stopped at its runtime before advancing, so Jellyfin's 90% rule marks it played. Nothing else can: the webview is suspended and its