diff --git a/lib/http/danmaku.dart b/lib/http/danmaku.dart index bf18d6491..8e4fdf6ec 100644 --- a/lib/http/danmaku.dart +++ b/lib/http/danmaku.dart @@ -85,7 +85,7 @@ abstract final class DanmakuHttp { if (res.data['code'] == 0) { return const Success(null); } else { - return Error(res.data['message']); + return Error(res.data['message'], code: res.data['code']); } } diff --git a/lib/pages/danmaku/controller.dart b/lib/pages/danmaku/controller.dart index 590af8e3a..fd12b79f4 100644 --- a/lib/pages/danmaku/controller.dart +++ b/lib/pages/danmaku/controller.dart @@ -1,3 +1,4 @@ +import 'dart:collection'; import 'dart:io' show File; import 'package:PiliPlus/grpc/bilibili/community/service/dm/v1.pb.dart'; @@ -10,28 +11,27 @@ import 'package:path/path.dart' as path; class PlDanmakuController { PlDanmakuController( - this.cid, - this.plPlayerController, - this.isFileSource, - ) : mergeDanmaku = plPlayerController.mergeDanmaku; + this._cid, + this._plPlayerController, + this._isFileSource, + ) : _mergeDanmaku = _plPlayerController.mergeDanmaku; - final int cid; - final PlPlayerController plPlayerController; - final bool mergeDanmaku; - final bool isFileSource; + final int _cid; + final PlPlayerController _plPlayerController; + final bool _mergeDanmaku; + final bool _isFileSource; - late final isLogin = Accounts.main.isLogin; + late final _isLogin = Accounts.main.isLogin; - Map> dmSegMap = {}; + final Map> _dmSegMap = {}; // 已请求的段落标记 - late final Set requestedSeg = {}; + late final Set _requestedSeg = {}; static const int segmentLength = 60 * 6 * 1000; void dispose() { - closed = true; - dmSegMap.clear(); - requestedSeg.clear(); + _dmSegMap.clear(); + _requestedSeg.clear(); } static int calcSegment(int progress) { @@ -39,80 +39,75 @@ class PlDanmakuController { } Future queryDanmaku(int segmentIndex) async { - if (isFileSource) { + if (_isFileSource) { return; } - if (requestedSeg.contains(segmentIndex)) { + if (_requestedSeg.contains(segmentIndex)) { return; } - requestedSeg.add(segmentIndex); + _requestedSeg.add(segmentIndex); final result = await DmGrpc.dmSegMobile( - cid: cid, + cid: _cid, segmentIndex: segmentIndex + 1, ); if (result.isSuccess) { final data = result.data; if (data.state == 1) { - plPlayerController.dmState.add(cid); + _plPlayerController.dmState.add(_cid); } handleDanmaku(data.elems); } else { - requestedSeg.remove(segmentIndex); + _requestedSeg.remove(segmentIndex); } } void handleDanmaku(List elems) { if (elems.isEmpty) return; - late final Map counts = {}; - if (mergeDanmaku) { - elems.retainWhere((item) { - int? count = counts[item.content]; - counts[item.content] = count != null ? count + 1 : 1; - return count == null; - }); - } + final uniques = HashMap(); - final shouldFilter = plPlayerController.filters.count != 0; + final shouldFilter = _plPlayerController.filters.count != 0; + final danmakuWeight = _plPlayerController.danmakuWeight; for (final element in elems) { - if (element.mode == 7 && !plPlayerController.showSpecialDanmaku) { - continue; - } - if (isLogin) { - element.isSelf = element.midHash == plPlayerController.midHash; + if (_isLogin) { + element.isSelf = element.midHash == _plPlayerController.midHash; } + if (!element.isSelf) { - if (element.weight < plPlayerController.danmakuWeight || - (shouldFilter && plPlayerController.filters.remove(element))) { + if (_mergeDanmaku) { + final elem = uniques[element.content]; + if (elem == null) { + uniques[element.content] = element..count = 1; + } else { + elem.count++; + continue; + } + } + + if (element.weight < danmakuWeight || + (shouldFilter && _plPlayerController.filters.remove(element))) { continue; } } - if (mergeDanmaku) { - final count = counts[element.content]; - if (count != 1) { - element.count = count!; - } - } + final int pos = element.progress ~/ 100; //每0.1秒存储一次 - (dmSegMap[pos] ??= []).add(element); + (_dmSegMap[pos] ??= []).add(element); } } List? getCurrentDanmaku(int progress) { - if (isFileSource) { + if (_isFileSource) { initFileDmIfNeeded(); } else { final int segmentIndex = calcSegment(progress); - if (!requestedSeg.contains(segmentIndex)) { + if (!_requestedSeg.contains(segmentIndex)) { queryDanmaku(segmentIndex); return null; } } - return dmSegMap[progress ~/ 100]; + return _dmSegMap[progress ~/ 100]; } - bool closed = false; - bool _fileDmLoaded = false; void initFileDmIfNeeded() { @@ -125,7 +120,7 @@ class PlDanmakuController { Future _initFileDm() async { try { final file = File( - path.join(plPlayerController.dirPath!, PathUtils.danmakuName), + path.join(_plPlayerController.dirPath!, PathUtils.danmakuName), ); if (!file.existsSync()) return; final bytes = await file.readAsBytes(); diff --git a/lib/pages/danmaku/view.dart b/lib/pages/danmaku/view.dart index 414d9db06..36ed70690 100644 --- a/lib/pages/danmaku/view.dart +++ b/lib/pages/danmaku/view.dart @@ -34,7 +34,7 @@ class PlDanmaku extends StatefulWidget { class _PlDanmakuState extends State { PlPlayerController get playerController => widget.playerController; - late PlDanmakuController _plDanmakuController; + late final PlDanmakuController _plDanmakuController; DanmakuController? _controller; int latestAddedPosition = -1; @@ -90,6 +90,7 @@ class _PlDanmakuState extends State { } } + @pragma('vm:notify-debugger-on-exception') void videoPositionListen(Duration position) { if (_controller == null || !playerController.enableShowDanmaku.value) { return; @@ -141,7 +142,7 @@ class _PlDanmakuState extends State { isColorful: playerController.showVipDanmaku && e.colorful == DmColorfulType.VipGradualColor, - count: e.hasCount() ? e.count : null, + count: e.count > 1 ? e.count : null, selfSend: e.isSelf, extra: VideoDanmaku( id: e.id.toInt(), diff --git a/lib/pages/setting/models/extra_settings.dart b/lib/pages/setting/models/extra_settings.dart index b7a30b121..b2c9782ce 100644 --- a/lib/pages/setting/models/extra_settings.dart +++ b/lib/pages/setting/models/extra_settings.dart @@ -536,13 +536,6 @@ List get extraSettings => [ setKey: SettingBoxKey.showVipDanmaku, defaultVal: true, ), - const SettingsModel( - settingsType: SettingsType.sw1tch, - title: '显示高级弹幕', - leading: Icon(MdiIcons.paletteAdvanced), - setKey: SettingBoxKey.showSpecialDanmaku, - defaultVal: false, - ), const SettingsModel( settingsType: SettingsType.sw1tch, title: '合并弹幕', diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index 8e227d572..9921a7ba2 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -13,6 +13,7 @@ import 'package:PiliPlus/http/danmaku.dart'; import 'package:PiliPlus/http/danmaku_block.dart'; import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/live.dart'; +import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/models/common/super_resolution_type.dart'; import 'package:PiliPlus/models/common/video/audio_quality.dart'; @@ -212,11 +213,12 @@ mixin HeaderMixin on State { /// 弹幕功能 void showSetDanmaku({bool isLive = false}) { // 屏蔽类型 - const List<({int value, String label})> blockTypesList = [ + const blockTypesList = [ (value: 5, label: '顶部'), (value: 2, label: '滚动'), (value: 4, label: '底部'), (value: 6, label: '彩色'), + (value: 7, label: '高级'), ]; final blockTypes = plPlayerController.blockTypes; // 智能云屏蔽 @@ -456,6 +458,7 @@ mixin HeaderMixin on State { hideTop: blockTypes.contains(5), hideBottom: blockTypes.contains(4), hideScroll: blockTypes.contains(2), + hideSpecial: blockTypes.contains(7), // 添加或修改其他需要修改的选项属性 ), ); @@ -827,6 +830,13 @@ class HeaderControl extends StatefulWidget { return true; } else { res.toast(); + if ((res as Error).code == 65006) { + extra.isLike = true; + return true; + } else if (res.code == 65004) { + extra.isLike = false; + return true; + } return false; } } diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index 0734df3e0..66c9b6dfc 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -359,7 +359,6 @@ class PlPlayerController { late int subtitlePaddingB = Pref.subtitlePaddingB; late double subtitleBgOpaticy = Pref.subtitleBgOpaticy; final bool showVipDanmaku = Pref.showVipDanmaku; // loop unswitching - final bool showSpecialDanmaku = Pref.showSpecialDanmaku; late double subtitleStrokeWidth = Pref.subtitleStrokeWidth; late int subtitleFontWeight = Pref.subtitleFontWeight; diff --git a/lib/utils/storage_key.dart b/lib/utils/storage_key.dart index 75d5d8fd4..febecdd82 100644 --- a/lib/utils/storage_key.dart +++ b/lib/utils/storage_key.dart @@ -183,7 +183,6 @@ abstract class SettingBoxKey { enableShowLiveDanmaku = 'enableShowLiveDanmaku', pipNoDanmaku = 'pipNoDanmaku', showVipDanmaku = 'showVipDanmaku', - showSpecialDanmaku = 'showSpecialDanmaku', mergeDanmaku = 'mergeDanmaku', danmakuWeight = 'danmakuWeight', danmakuBlockType = 'danmakuBlockType', diff --git a/lib/utils/storage_pref.dart b/lib/utils/storage_pref.dart index 002ea60d7..b9363ccee 100644 --- a/lib/utils/storage_pref.dart +++ b/lib/utils/storage_pref.dart @@ -404,9 +404,6 @@ abstract class Pref { static bool get showVipDanmaku => _setting.get(SettingBoxKey.showVipDanmaku, defaultValue: true); - static bool get showSpecialDanmaku => - _setting.get(SettingBoxKey.showSpecialDanmaku, defaultValue: false); - static bool get mergeDanmaku => _setting.get(SettingBoxKey.mergeDanmaku, defaultValue: false);