import { useEffect, useRef } from 'react' import type { BaseItemDto } from '../api/types' import { useTrakt } from '../stores/trakt-store' import { scrobbleStart, scrobblePause, scrobbleStop } from '../lib/trakt' interface Args { item: BaseItemDto | null | undefined isPaused: boolean currentTime: number duration: number } /** * Fire Trakt scrobble calls in response to local playback transitions. * * - start on first play * - pause on pause * - resume sends another start * - stop on unmount (covers navigating away mid-playback) * * Progress + duration are tracked through refs so the stop-on-unmount * effect (which only re-binds when the item changes) sees the latest * values rather than the ones captured at mount. Scrobble transitions * key off `isPaused` only - they shouldn't fire on every time-update tick. */ export function useTraktScrobble({ item, isPaused, currentTime, duration }: Args) { const tokens = useTrakt(s => s.tokens) const enabled = useTrakt(s => s.enabled) const lastState = useRef<'idle' | 'playing' | 'paused'>('idle') const lastItemId = useRef(null) const progressRef = useRef({ currentTime: 0, duration: 0 }) // Keep progress in a ref so cleanup callbacks see the latest value. progressRef.current = { currentTime, duration } // Reset when item changes useEffect(() => { if (item?.Id && item.Id !== lastItemId.current) { lastState.current = 'idle' lastItemId.current = item.Id } }, [item?.Id]) // State transitions. Only depends on isPaused - currentTime updates // would otherwise re-run this effect dozens of times a second. useEffect(() => { if (!enabled || !tokens || !item) return const { currentTime: t, duration: d } = progressRef.current const pct = d > 0 ? (t / d) * 100 : 0 if (isPaused) { if (lastState.current === 'playing') { lastState.current = 'paused' scrobblePause(item, pct).catch(() => {}) } } else { if (lastState.current !== 'playing') { lastState.current = 'playing' scrobbleStart(item, pct).catch(() => {}) } } }, [enabled, tokens, item, isPaused]) // Stop scrobble on unmount or item swap. Reads progress from the ref // so the percentage reflects where the user actually stopped. useEffect(() => { const captured = item return () => { if (!useTrakt.getState().enabled) return if (!useTrakt.getState().tokens) return if (!captured) return if (lastState.current === 'idle') return const { currentTime: t, duration: d } = progressRef.current const pct = d > 0 ? (t / d) * 100 : 0 scrobbleStop(captured, pct).catch(() => {}) lastState.current = 'idle' } }, [item]) }