Files
2026-07-14 11:11:36 +08:00

106 lines
2.7 KiB
Dart

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<void> 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<void> 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<void> 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;
}
}