fix(plex): support no-burn transcode subtitles

This commit is contained in:
edde746
2026-05-20 17:21:31 +02:00
parent 2b167a60f5
commit c93a266722
34 changed files with 1103 additions and 192 deletions
+29 -10
View File
@@ -46,6 +46,8 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
int _lastEmitMs = 0;
int _lastCacheStateMs = 0;
int _positionMs = 0;
Duration _timelineOffset = Duration.zero;
Duration? _timelineDuration;
int _nextPropId = 0;
final Map<int, String> _propIdToName = {};
@@ -142,13 +144,13 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
case 'time-pos':
if (value is num) {
_positionMs = (value * 1000).round();
final pos = _toTimelinePosition(Duration(milliseconds: (value * 1000).round()));
_positionMs = pos.inMilliseconds;
// Only allocate Duration + copyWith + emit at ~4Hz (250ms).
// Raw int is stored every tick so synchronous reads via _positionMs stay current.
final nowMs = _throttleSw.elapsedMilliseconds;
if (nowMs - _lastEmitMs >= 250) {
_lastEmitMs = nowMs;
final pos = Duration(milliseconds: _positionMs);
_state = _state.copyWith(position: pos);
positionController.add(pos);
}
@@ -157,7 +159,7 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
case 'duration':
if (value is num) {
final duration = Duration(milliseconds: (value * 1000).toInt());
final duration = _timelineDuration ?? _toTimelinePosition(Duration(milliseconds: (value * 1000).toInt()));
_state = _state.copyWith(duration: duration);
durationController.add(duration);
}
@@ -174,7 +176,7 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
final nowMs = _throttleSw.elapsedMilliseconds;
if (nowMs - _lastCacheStateMs < 250) break;
_lastCacheStateMs = nowMs;
final buffer = Duration(milliseconds: (value * 1000).toInt());
final buffer = _toTimelinePosition(Duration(milliseconds: (value * 1000).toInt()));
_state = _state.copyWith(buffer: buffer);
bufferController.add(buffer);
// Synthesize a single range for players without demuxer-cache-state (ExoPlayer).
@@ -295,7 +297,7 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
// Extract cache-end for the single buffer duration (replaces demuxer-cache-time)
final cacheEnd = cacheState['cache-end'] as num?;
if (cacheEnd != null) {
final buffer = Duration(milliseconds: (cacheEnd * 1000).toInt());
final buffer = _toTimelinePosition(Duration(milliseconds: (cacheEnd * 1000).toInt()));
_state = _state.copyWith(buffer: buffer);
bufferController.add(buffer);
}
@@ -311,8 +313,8 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
if (start != null && end != null) {
ranges.add(
BufferRange(
start: Duration(milliseconds: (start * 1000).toInt()),
end: Duration(milliseconds: (end * 1000).toInt()),
start: _toTimelinePosition(Duration(milliseconds: (start * 1000).toInt())),
end: _toTimelinePosition(Duration(milliseconds: (end * 1000).toInt())),
),
);
}
@@ -491,18 +493,35 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
}
@protected
void resetPlaybackProgress(Duration position) {
void configureTimeline({Duration offset = Duration.zero, Duration? duration}) {
_timelineOffset = offset;
_timelineDuration = duration;
}
@protected
Duration sourceSeekPosition(Duration timelinePosition) {
final sourcePosition = timelinePosition - _timelineOffset;
return sourcePosition.isNegative ? Duration.zero : sourcePosition;
}
Duration _toTimelinePosition(Duration sourcePosition) {
return sourcePosition + _timelineOffset;
}
@protected
void resetPlaybackProgress(Duration sourcePosition) {
final position = _toTimelinePosition(sourcePosition);
_positionMs = position.inMilliseconds;
_state = _state.copyWith(
completed: false,
position: position,
duration: Duration.zero,
duration: _timelineDuration ?? Duration.zero,
buffer: Duration.zero,
bufferRanges: const [],
);
completedController.add(false);
positionController.add(position);
durationController.add(Duration.zero);
durationController.add(_timelineDuration ?? Duration.zero);
bufferController.add(Duration.zero);
bufferRangesController.add(const []);
}