From 7b05ef55aeeb0ff1a4cc3472d387de78a112f296 Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Fri, 28 Aug 2026 20:50:26 -0600 Subject: [PATCH] fix(listen-log): a gapless hand-off closes the previous row as natural, not skip Under gapless the engine never reports a not-playing tick between two tracks, so the poll loop's track_ended edge does not fire and the next track's edge found the previous row still open and closed it as skip (smoke: 229 s of a 230 s track recorded as skip). The Qt edge now uses the tracker's inference (last observed position within 2 s of the duration = natural), the same rule qbzd already applies. cc --- crates/qbz-qt/src/listen_log_qt.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/crates/qbz-qt/src/listen_log_qt.rs b/crates/qbz-qt/src/listen_log_qt.rs index 62270943d..0d3a7058e 100644 --- a/crates/qbz-qt/src/listen_log_qt.rs +++ b/crates/qbz-qt/src/listen_log_qt.rs @@ -90,7 +90,14 @@ pub async fn on_track_edge(track: &QueueTrack, event: &PlaybackEvent) { .bit_perfect_mode .map(|m| format!("{m:?}").to_ascii_lowercase()); let meta = meta_from_queue_track(track, event.bit_depth, event.sample_rate, backend); - logger.track_started(meta, false).await; + // `infer_end = true`: under GAPLESS the engine hands off to the next + // track without ever reporting a not-playing tick, so the poll loop's + // `track_ended` predicate never fires and the previous row would close + // as a skip although it played to its last second (smoke 2026-08-28: + // 229 s of 230 s recorded as skip). The tracker's 2 s window on the last + // observed position tells the two apart; when the explicit natural-end + // edge DID fire first, no row is open and the flag is moot. + logger.track_started(meta, true).await; } /// One poll tick. `position_secs` is the engine's whole-second position;