import 'dart:async'; import '../../../core/contracts/playback.dart'; import '../../../core/domain/ports/emby_gateway.dart'; import '../../../shared/utils/app_logger.dart'; typedef PlaybackReportPayloadBuilder = PlaybackReportPayload Function({required bool isPaused, String? eventName}); class EmbyPlaybackReporter { EmbyPlaybackReporter({ required EmbyGateway gateway, required AuthedRequestContext context, this.enabled = true, }) : _gateway = gateway, _context = context; static const _tag = 'Reporter'; final EmbyGateway _gateway; final AuthedRequestContext _context; final bool enabled; bool _startedReported = false; bool _stoppedReported = false; Timer? _progressTimer; bool get startedReported => _startedReported; bool get stoppedReported => _stoppedReported; Future reportStarted(PlaybackReportPayload payload) async { if (!enabled) return; if (_startedReported) return; _startedReported = true; try { await _gateway.reportPlaybackStarted(ctx: _context, payload: payload); } catch (e) { AppLogger.warn(_tag, 'Start report failed', e); } } Future reportProgress(PlaybackReportPayload payload) async { if (!_startedReported) return; try { await _gateway.reportPlaybackProgress(ctx: _context, payload: payload); } catch (e) { AppLogger.warn(_tag, 'Progress report failed', e); } } Future reportStopped(PlaybackReportPayload payload) async { if (!enabled) return; if (!_startedReported) { AppLogger.debug(_tag, 'stop report skipped: start not reported'); return; } if (_stoppedReported) { AppLogger.debug(_tag, 'stop report skipped: already stopped'); return; } _stoppedReported = true; _progressTimer?.cancel(); final sw = Stopwatch()..start(); try { await _gateway.reportPlaybackStopped(ctx: _context, payload: payload); AppLogger.debug(_tag, 'stop report ok in ${sw.elapsedMilliseconds}ms'); } catch (e) { AppLogger.warn( _tag, 'Stop report failed after ${sw.elapsedMilliseconds}ms', e, ); } } void startProgressTimer(PlaybackReportPayloadBuilder payloadBuilder) { if (!enabled) return; if (_progressTimer != null) return; _progressTimer = Timer.periodic(const Duration(seconds: 8), (_) { if (_startedReported && !_stoppedReported) { unawaited( reportProgress( payloadBuilder(isPaused: false, eventName: 'TimeUpdate'), ), ); } }); } void reset() { _progressTimer?.cancel(); _progressTimer = null; _startedReported = false; _stoppedReported = false; } void dispose() { _progressTimer?.cancel(); _progressTimer = null; } }