From 1b010d40817cb0abb4238252e3b9bc1bb1a4b9e0 Mon Sep 17 00:00:00 2001 From: Mattias Thall Date: Wed, 27 May 2026 01:19:47 +0200 Subject: [PATCH] Track video clicks as engagement signals - stats: started_count now includes any video opened (last_watched_at set) not just ones with saved progress seconds - VideoPlayer: fires updateProgress immediately on open so even a click-and-back sets last_watched_at and counts as a started video Co-Authored-By: Claude Sonnet 4.6 --- backend/routers/stats.py | 2 +- frontend/src/components/VideoPlayer.jsx | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/backend/routers/stats.py b/backend/routers/stats.py index 5cc263d..a19829d 100644 --- a/backend/routers/stats.py +++ b/backend/routers/stats.py @@ -140,7 +140,7 @@ def get_stats( text(""" SELECT COUNT(*) AS n FROM user_videos WHERE user_id = :uid AND watched = 0 - AND watch_progress_seconds > 0 + AND (watch_progress_seconds > 0 OR last_watched_at IS NOT NULL) """), {"uid": uid}, ).mappings().first() diff --git a/frontend/src/components/VideoPlayer.jsx b/frontend/src/components/VideoPlayer.jsx index 7f32e1d..8ce2dcb 100644 --- a/frontend/src/components/VideoPlayer.jsx +++ b/frontend/src/components/VideoPlayer.jsx @@ -126,6 +126,16 @@ export default function VideoPlayer() { } }, [dlStatus?.status]); // eslint-disable-line react-hooks/exhaustive-deps + // Record a "clicked" impression as soon as we have the video id — even if the + // user closes immediately before playback starts. + const clickedRef = useRef(false); + useEffect(() => { + if (video?.id && !clickedRef.current && !video.is_watched) { + clickedRef.current = true; + updateProgress(video.id, { watch_progress_seconds: video.watch_progress_seconds ?? 0 }); + } + }, [video?.id]); // eslint-disable-line react-hooks/exhaustive-deps + // ── Trigger download on open ────────────────────────────────────────────── const downloadMut = useMutation({ mutationFn: (ytId) => createDownload(ytId),