diff --git a/lib/http/danmaku.dart b/lib/http/danmaku.dart index 7b002afd..a9b19cbd 100644 --- a/lib/http/danmaku.dart +++ b/lib/http/danmaku.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/grpc/dm/v1/dm.pb.dart'; +import 'package:PiliPlus/utils/extension.dart'; import 'package:dio/dio.dart'; import 'index.dart'; @@ -7,6 +8,7 @@ class DanmakaHttp { static Future queryDanmaku({ required int cid, required int segmentIndex, + required bool mergeDanmaku, }) async { // 构建参数对象 Map params = { @@ -22,7 +24,11 @@ class DanmakaHttp { if (response.statusCode != 200 || response.data == null) { return DmSegMobileReply(); } - return DmSegMobileReply.fromBuffer(response.data); + DmSegMobileReply data = DmSegMobileReply.fromBuffer(response.data); + if (mergeDanmaku) { + data.elems.unique((item) => item.content); + } + return data; } static Future shootDanmaku({ diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index 6a4c7db6..868d9be9 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -1,6 +1,7 @@ import 'package:PiliPlus/grpc/dm/v1/dm.pb.dart'; import 'package:PiliPlus/http/danmaku.dart'; import 'package:PiliPlus/plugin/pl_player/controller.dart'; +import 'package:PiliPlus/utils/storage.dart'; class PlDanmakuController { PlDanmakuController( @@ -18,6 +19,8 @@ class PlDanmakuController { static int segmentLength = 60 * 6 * 1000; + late final mergeDanmaku = GStorage.mergeDanmaku; + void initiate(int videoDuration, int progress) { if (videoDuration <= 0) { return; @@ -45,7 +48,10 @@ class PlDanmakuController { assert(requestedSeg[segmentIndex] == false); requestedSeg[segmentIndex] = true; final DmSegMobileReply result = await DanmakaHttp.queryDanmaku( - cid: cid, segmentIndex: segmentIndex + 1); + cid: cid, + segmentIndex: segmentIndex + 1, + mergeDanmaku: mergeDanmaku, + ); if (result.elems.isNotEmpty) { for (var element in result.elems) { int pos = element.progress ~/ 100; //每0.1秒存储一次 diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index 3b226537..f4404ffb 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -1754,6 +1754,14 @@ List get extraSettings => [ setKey: SettingBoxKey.showVipDanmaku, defaultVal: true, ), + SettingsModel( + settingsType: SettingsType.sw1tch, + title: '合并弹幕', + subtitle: '合并一段时间内获取到的相同弹幕', + leading: Icon(Icons.merge), + setKey: SettingBoxKey.mergeDanmaku, + defaultVal: false, + ), SettingsModel( settingsType: SettingsType.sw1tch, enableFeedback: true, diff --git a/lib/utils/extension.dart b/lib/utils/extension.dart index 78e4d77f..dfdf947b 100644 --- a/lib/utils/extension.dart +++ b/lib/utils/extension.dart @@ -88,3 +88,12 @@ extension BuildContextExt on BuildContext { ); } } + +extension Unique on List { + List unique([Id Function(E element)? id, bool inplace = true]) { + final ids = {}; + var list = inplace ? this : List.from(this); + list.retainWhere((x) => ids.add(id != null ? id(x) : x as Id)); + return list; + } +} diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index f6658cc8..552f1956 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -339,6 +339,9 @@ class GStorage { static bool get showVipDanmaku => GStorage.setting.get(SettingBoxKey.showVipDanmaku, defaultValue: true); + static bool get mergeDanmaku => + GStorage.setting.get(SettingBoxKey.mergeDanmaku, defaultValue: false); + static List get dynamicDetailRatio => List.from(setting .get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0])); @@ -558,6 +561,7 @@ class SettingBoxKey { refreshDragPercentage = 'refreshDragPercentage', refreshDisplacement = 'refreshDisplacement', showVipDanmaku = 'showVipDanmaku', + mergeDanmaku = 'mergeDanmaku', // Sponsor Block enableSponsorBlock = 'enableSponsorBlock',