106 lines
2.7 KiB
Dart
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;
|
||
|
|
}
|
||
|
|
}
|