diff --git a/lib/http/danmaku.dart b/lib/http/danmaku.dart index 9fa11cdd7..d1eff0f50 100644 --- a/lib/http/danmaku.dart +++ b/lib/http/danmaku.dart @@ -2,15 +2,15 @@ import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart'; import 'package:PiliPlus/grpc/grpc_repo.dart'; import 'package:PiliPlus/http/api.dart'; import 'package:PiliPlus/http/init.dart'; +import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:dio/dio.dart'; class DanmakuHttp { // 获取视频弹幕 - static Future queryDanmaku({ + static Future> queryDanmaku({ required int cid, required int segmentIndex, - required bool mergeDanmaku, int queryCount = 1, }) async { // 构建参数对象 @@ -18,34 +18,18 @@ class DanmakuHttp { await GrpcRepo.dmSegMobile(cid: cid, segmentIndex: segmentIndex); if (!response['status']) { if (queryCount >= 3) { - return {'status': false}; + return const Error(''); } else { await Future.delayed(const Duration(seconds: 1)); return await queryDanmaku( cid: cid, segmentIndex: segmentIndex, - mergeDanmaku: mergeDanmaku, queryCount: ++queryCount, ); } } DmSegMobileReply data = response['data']; - if (mergeDanmaku && data.elems.isNotEmpty) { - final Map counts = {}; - data.elems.retainWhere((item) { - int? count = counts[item.content]; - counts[item.content] = count != null ? count + 1 : 1; - return count == null; - }); - for (DanmakuElem item in data.elems) { - item.clearAttr(); - final count = counts[item.content]; - if (count != 1) { - item.attr = count; - } - } - } - return {'status': true, 'data': data}; + return LoadingState.success(data); } static Future shootDanmaku({ diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index fe828c3b0..03e6ba86b 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -6,15 +6,16 @@ class PlDanmakuController { PlDanmakuController( this.cid, this.plPlayerController, - ); + ) : mergeDanmaku = plPlayerController.mergeDanmaku; final int cid; final PlPlayerController plPlayerController; + final bool mergeDanmaku; Map> dmSegMap = {}; // 已请求的段落标记 - Map requestedSeg = {}; + Set requestedSeg = {}; - static int segmentLength = 60 * 6 * 1000; + static const int segmentLength = 60 * 6 * 1000; void dispose() { dmSegMap.clear(); @@ -26,36 +27,48 @@ class PlDanmakuController { } Future queryDanmaku(int segmentIndex) async { - if (requestedSeg[segmentIndex] == true) { + if (requestedSeg.contains(segmentIndex)) { return; } - requestedSeg[segmentIndex] = true; - final Map result = await DanmakuHttp.queryDanmaku( + requestedSeg.add(segmentIndex); + final result = await DanmakuHttp.queryDanmaku( cid: cid, segmentIndex: segmentIndex + 1, - mergeDanmaku: plPlayerController.mergeDanmaku, ); - if (result['status']) { - if (result['data'].elems.isNotEmpty) { - for (DanmakuElem element in result['data'].elems) { - if (element.mode == 7 && !plPlayerController.showSpecialDanmaku) { - continue; + + if (result.isSuccess) { + final data = result.data; + if (data.elems.isNotEmpty) { + final Map counts = {}; + if (mergeDanmaku) { + data.elems.retainWhere((item) { + int? count = counts[item.content]; + counts[item.content] = count != null ? count + 1 : 1; + return count == null; + }); + } + + for (final element in data.elems) { + if (mergeDanmaku) { + final count = counts[element.content]; + if (count != 1) { + element.attr = count!; + } else { + element.clearAttr(); + } } int pos = element.progress ~/ 100; //每0.1秒存储一次 - if (dmSegMap[pos] == null) { - dmSegMap[pos] = []; - } - dmSegMap[pos]!.add(element); + (dmSegMap[pos] ??= []).add(element); } } } else { - requestedSeg[segmentIndex] = false; + requestedSeg.remove(segmentIndex); } } List? getCurrentDanmaku(int progress) { int segmentIndex = calcSegment(progress); - if (requestedSeg[segmentIndex] != true) { + if (!requestedSeg.contains(segmentIndex)) { queryDanmaku(segmentIndex); return null; } diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 055d09f01..65f6bf795 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -1264,13 +1264,13 @@ class HeaderControlState extends State { /// 弹幕功能 void showSetDanmaku() { // 屏蔽类型 - const List> blockTypesList = [ - {'value': 5, 'label': '顶部'}, - {'value': 2, 'label': '滚动'}, - {'value': 4, 'label': '底部'}, - {'value': 6, 'label': '彩色'}, + const List<({int value, String label})> blockTypesList = [ + (value: 5, label: '顶部'), + (value: 2, label: '滚动'), + (value: 4, label: '底部'), + (value: 6, label: '彩色'), ]; - final List blockTypes = widget.controller.blockTypes; + final blockTypes = widget.controller.blockTypes; // 智能云屏蔽 int danmakuWeight = widget.controller.danmakuWeight; // 显示区域 @@ -1501,16 +1501,14 @@ class HeaderControlState extends State { padding: const EdgeInsets.only(top: 12), child: Row( children: [ - for (final Map i + for (final (value: value, label: label) in blockTypesList) ...[ ActionRowLineItem( onTap: () { - final bool isChoose = - blockTypes.contains(i['value']); - if (isChoose) { - blockTypes.remove(i['value']); + if (blockTypes.contains(value)) { + blockTypes.remove(value); } else { - blockTypes.add(i['value']); + blockTypes.add(value); } widget.controller ..blockTypes = blockTypes @@ -1527,8 +1525,8 @@ class HeaderControlState extends State { ); } catch (_) {} }, - text: i['label'], - selectStatus: blockTypes.contains(i['value']), + text: label, + selectStatus: blockTypes.contains(value), ), const SizedBox(width: 10), ] diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index f00e4b5a0..98fc7f6fa 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -249,7 +249,7 @@ class PlPlayerController { bool showDanmaku = true; late final mergeDanmaku = GStorage.mergeDanmaku; // 弹幕相关配置 - late List blockTypes; + late Set blockTypes; late double showArea; late double opacity; late double fontSize; @@ -434,7 +434,11 @@ class PlPlayerController { setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: true); danmakuWeight = setting.get(SettingBoxKey.danmakuWeight, defaultValue: 0); filters = GStorage.danmakuFilterRule; - blockTypes = setting.get(SettingBoxKey.danmakuBlockType, defaultValue: []); + blockTypes = + (setting.get(SettingBoxKey.danmakuBlockType, defaultValue: []) + as Iterable) + .cast() + .toSet(); showArea = setting.get(SettingBoxKey.danmakuShowArea, defaultValue: 0.5); // 不透明度 opacity = setting.get(SettingBoxKey.danmakuOpacity, defaultValue: 1.0); @@ -1484,7 +1488,7 @@ class PlPlayerController { void putDanmakuSettings() { setting ..put(SettingBoxKey.danmakuWeight, danmakuWeight) - ..put(SettingBoxKey.danmakuBlockType, blockTypes) + ..put(SettingBoxKey.danmakuBlockType, blockTypes.toList()) ..put(SettingBoxKey.danmakuShowArea, showArea) ..put(SettingBoxKey.danmakuOpacity, opacity) ..put(SettingBoxKey.danmakuFontScale, fontSize)