Files
sm-emby-share/lib/core/media/embedded_subtitle_cues.dart
T
2026-07-14 11:11:36 +08:00

69 lines
1.5 KiB
Dart

class TimedSubtitle {
final Duration start;
final Duration end;
final String text;
const TimedSubtitle({
required this.start,
required this.end,
required this.text,
});
}
class EmbeddedSubtitleCues {
final List<TimedSubtitle> _cues = [];
bool get isEmpty => _cues.isEmpty;
void add(double startSec, double endSec, List<String> lines) {
final text = lines
.map((s) => s.trim())
.where((s) => s.isNotEmpty)
.join('\n');
if (text.isEmpty) return;
final start = _toDuration(startSec);
final end = _toDuration(endSec);
if (end < start) return;
final at = _lowerBound(start);
for (var i = at; i < _cues.length && _cues[i].start == start; i++) {
if (_cues[i].end == end && _cues[i].text == text) return;
}
_cues.insert(at, TimedSubtitle(start: start, end: end, text: text));
}
List<String> textAt(Duration position) {
final out = <String>[];
for (final cue in _cues) {
if (position < cue.start) break;
if (position <= cue.end) out.addAll(cue.text.split('\n'));
}
return out;
}
void clear() => _cues.clear();
static Duration _toDuration(double seconds) =>
Duration(milliseconds: (seconds * 1000).round());
int _lowerBound(Duration start) {
int lo = 0;
int hi = _cues.length;
while (lo < hi) {
final mid = (lo + hi) >> 1;
if (_cues[mid].start < start) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
}