feat: fallback skip markers from chapter titles

This commit is contained in:
edde746
2026-02-22 04:34:36 +01:00
parent 8ef0d2e25c
commit 3289ce0fbc
3 changed files with 49 additions and 2 deletions
+47
View File
@@ -183,4 +183,51 @@ class PlaybackExtras {
final List<PlexMarker> markers; final List<PlexMarker> markers;
PlaybackExtras({required this.chapters, required this.markers}); PlaybackExtras({required this.chapters, required this.markers});
static final _introPattern = RegExp(
r'(?:^|\b)(?:intro(?:duction)?|opening)(?:\b|$)|^op(?:\s?\d+)?$',
caseSensitive: false,
);
static final _creditsPattern = RegExp(
r'(?:^|\b)(?:outro|closing|credits?|ending)(?:\b|$)|^ed(?:\s?\d+)?$',
caseSensitive: false,
);
static String? _classifyChapterTitle(String title) {
if (_introPattern.hasMatch(title)) return 'intro';
if (_creditsPattern.hasMatch(title)) return 'credits';
return null;
}
/// Returns [PlaybackExtras] using real markers when available, otherwise
/// synthesises markers from chapter titles matching intro/credits patterns.
factory PlaybackExtras.withChapterFallback({
required List<PlexChapter> chapters,
required List<PlexMarker> markers,
}) {
if (markers.isNotEmpty) {
return PlaybackExtras(chapters: chapters, markers: markers);
}
final synthetic = <PlexMarker>[];
for (var i = 0; i < chapters.length; i++) {
final ch = chapters[i];
final title = ch.title;
if (title == null || title.isEmpty) continue;
final type = _classifyChapterTitle(title);
if (type == null) continue;
final start = ch.startTimeOffset;
if (start == null) continue;
final end = ch.endTimeOffset ??
(i + 1 < chapters.length ? chapters[i + 1].startTimeOffset : null);
if (end == null) continue;
synthetic.add(PlexMarker(id: ch.id, type: type, startTimeOffset: start, endTimeOffset: end));
}
return PlaybackExtras(chapters: chapters, markers: synthetic);
}
} }
+1 -1
View File
@@ -997,7 +997,7 @@ class PlexClient {
} }
} }
return PlaybackExtras(chapters: chapters, markers: markers); return PlaybackExtras.withChapterFallback(chapters: chapters, markers: markers);
} }
/// Get consolidated video playback data (URL, media info, versions, and markers) in a single API call. /// Get consolidated video playback data (URL, media info, versions, and markers) in a single API call.
@@ -885,7 +885,7 @@ class _PlexVideoControlsState extends State<PlexVideoControls> with WindowListen
} }
} }
return PlaybackExtras(chapters: chapters, markers: markers); return PlaybackExtras.withChapterFallback(chapters: chapters, markers: markers);
} }
Widget _buildTrackChapterControlsWidget() { Widget _buildTrackChapterControlsWidget() {