56 lines
1.4 KiB
Dart
56 lines
1.4 KiB
Dart
import '../contracts/danmaku.dart';
|
|
|
|
const defaultDuplicateDanmakuMergeWindowSeconds = 1.0;
|
|
|
|
final _whitespacePattern = RegExp(r'\s+');
|
|
|
|
List<DanmakuComment> mergeDuplicateDanmakuComments(
|
|
Iterable<DanmakuComment> comments, {
|
|
double windowSeconds = defaultDuplicateDanmakuMergeWindowSeconds,
|
|
}) {
|
|
if (windowSeconds < 0) {
|
|
throw ArgumentError.value(
|
|
windowSeconds,
|
|
'windowSeconds',
|
|
'must be non-negative',
|
|
);
|
|
}
|
|
|
|
final sorted = comments.toList()..sort(_compareDanmakuComments);
|
|
if (sorted.length < 2) return sorted;
|
|
|
|
|
|
final keptByText = <String, List<DanmakuComment>>{};
|
|
final passthrough = <DanmakuComment>[];
|
|
|
|
for (final comment in sorted) {
|
|
final key = _mergeKey(comment);
|
|
if (key.isEmpty) {
|
|
passthrough.add(comment);
|
|
continue;
|
|
}
|
|
|
|
final kept = keptByText.putIfAbsent(key, () => []);
|
|
final windowStart = kept.isEmpty ? null : kept.last.time;
|
|
if (windowStart == null || comment.time - windowStart > windowSeconds) {
|
|
kept.add(comment);
|
|
}
|
|
}
|
|
|
|
return <DanmakuComment>[
|
|
...passthrough,
|
|
for (final kept in keptByText.values) ...kept,
|
|
]..sort(_compareDanmakuComments);
|
|
}
|
|
|
|
int _compareDanmakuComments(DanmakuComment a, DanmakuComment b) {
|
|
final timeOrder = a.time.compareTo(b.time);
|
|
if (timeOrder != 0) return timeOrder;
|
|
return a.cid.compareTo(b.cid);
|
|
}
|
|
|
|
String _mergeKey(DanmakuComment comment) {
|
|
return comment.text.trim().replaceAll(_whitespacePattern, ' ');
|
|
}
|
|
|