feat: 新增弹幕按等级云屏蔽功能

This commit is contained in:
orz12
2024-04-04 11:05:23 +08:00
parent 38543ed8f2
commit 51244c58f9
5 changed files with 72 additions and 6 deletions

View File

@@ -1,9 +1,12 @@
import 'package:PiliPalaX/http/danmaku.dart'; import 'package:PiliPalaX/http/danmaku.dart';
import 'package:PiliPalaX/models/danmaku/dm.pb.dart'; import 'package:PiliPalaX/models/danmaku/dm.pb.dart';
import 'package:flutter/cupertino.dart';
class PlDanmakuController { class PlDanmakuController {
PlDanmakuController(this.cid); PlDanmakuController(this.cid, this.danmakuWeightNotifier);
final int cid; final int cid;
final ValueNotifier<int> danmakuWeightNotifier;
int danmakuWeight = 0;
Map<int, List<DanmakuElem>> dmSegMap = {}; Map<int, List<DanmakuElem>> dmSegMap = {};
// 已请求的段落标记 // 已请求的段落标记
List<bool> requestedSeg = []; List<bool> requestedSeg = [];
@@ -16,6 +19,11 @@ class PlDanmakuController {
if (videoDuration <= 0) { if (videoDuration <= 0) {
return; return;
} }
danmakuWeightNotifier.addListener(() {
print(
"danmakuWeight changed from $danmakuWeight to ${danmakuWeightNotifier.value}");
danmakuWeight = danmakuWeightNotifier.value;
});
if (requestedSeg.isEmpty) { if (requestedSeg.isEmpty) {
int segCount = (videoDuration / segmentLength).ceil(); int segCount = (videoDuration / segmentLength).ceil();
requestedSeg = List<bool>.generate(segCount, (index) => false); requestedSeg = List<bool>.generate(segCount, (index) => false);
@@ -59,6 +67,13 @@ class PlDanmakuController {
if (!requestedSeg[segmentIndex]) { if (!requestedSeg[segmentIndex]) {
queryDanmaku(segmentIndex); queryDanmaku(segmentIndex);
} }
if (danmakuWeight == 0) {
return dmSegMap[progress ~/ 100]; return dmSegMap[progress ~/ 100];
} else {
//using filter
return dmSegMap[progress ~/ 100]
?.where((element) => element.weight >= danmakuWeight)
.toList();
}
} }
} }

View File

@@ -43,7 +43,8 @@ class _PlDanmakuState extends State<PlDanmaku> {
super.initState(); super.initState();
enableShowDanmaku = enableShowDanmaku =
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false); setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
_plDanmakuController = PlDanmakuController(widget.cid); _plDanmakuController = PlDanmakuController(
widget.cid, widget.playerController.danmakuWeight);
if (mounted) { if (mounted) {
playerController = widget.playerController; playerController = widget.playerController;
if (enableShowDanmaku || playerController.isOpenDanmu.value) { if (enableShowDanmaku || playerController.isOpenDanmu.value) {
@@ -136,8 +137,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
hideTop: blockTypes.contains(5), hideTop: blockTypes.contains(5),
hideScroll: blockTypes.contains(2), hideScroll: blockTypes.contains(2),
hideBottom: blockTypes.contains(4), hideBottom: blockTypes.contains(4),
duration: duration: danmakuDurationVal / playerController.playbackSpeed,
danmakuDurationVal / playerController.playbackSpeed,
strokeWidth: strokeWidth, strokeWidth: strokeWidth,
// initDuration / // initDuration /
// (danmakuSpeedVal * widget.playerController.playbackSpeed), // (danmakuSpeedVal * widget.playerController.playbackSpeed),

View File

@@ -23,6 +23,7 @@ import '../../../../models/video_detail_res.dart';
import '../../../../services/service_locator.dart'; import '../../../../services/service_locator.dart';
import '../introduction/index.dart'; import '../introduction/index.dart';
import 'package:marquee/marquee.dart'; import 'package:marquee/marquee.dart';
import '../../../danmaku/controller.dart';
class HeaderControl extends StatefulWidget implements PreferredSizeWidget { class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
const HeaderControl({ const HeaderControl({
@@ -714,6 +715,9 @@ class _HeaderControlState extends State<HeaderControl> {
{'value': 0.75, 'label': '3/4屏'}, {'value': 0.75, 'label': '3/4屏'},
{'value': 1.0, 'label': '满屏'}, {'value': 1.0, 'label': '满屏'},
]; ];
// 智能云屏蔽
int danmakuWeight = widget.controller!.danmakuWeight.value;
// 显示区域
double showArea = widget.controller!.showArea; double showArea = widget.controller!.showArea;
// 不透明度 // 不透明度
double opacityVal = widget.controller!.opacityVal; double opacityVal = widget.controller!.opacityVal;
@@ -752,6 +756,46 @@ class _HeaderControlState extends State<HeaderControl> {
child: Center(child: Text('弹幕设置', style: titleStyle)), child: Center(child: Text('弹幕设置', style: titleStyle)),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Text('智能云屏蔽 $danmakuWeight'),
Padding(
padding: const EdgeInsets.only(
top: 0,
bottom: 6,
left: 10,
right: 10,
),
child: SliderTheme(
data: SliderThemeData(
trackShape: MSliderTrackShape(),
thumbColor: Theme.of(context).colorScheme.primary,
activeTrackColor: Theme.of(context).colorScheme.primary,
trackHeight: 10,
thumbShape: const RoundSliderThumbShape(
enabledThumbRadius: 6.0),
),
child: Slider(
min: 0,
max: 10,
value: danmakuWeight.toDouble(),
divisions: 10,
label: '$danmakuWeight',
onChanged: (double val) {
danmakuWeight = val.toInt();
widget.controller!.danmakuWeight.value =
danmakuWeight;
widget.controller!.putDanmakuSettings();
setState(() {});
// try {
// final DanmakuOption currentOption =
// danmakuController.option;
// final DanmakuOption updatedOption =
// currentOption.copyWith(strokeWidth: val);
// danmakuController.updateOption(updatedOption);
// } catch (_) {}
},
),
),
),
const Text('按类型屏蔽'), const Text('按类型屏蔽'),
Padding( Padding(
padding: const EdgeInsets.only(top: 12, bottom: 18), padding: const EdgeInsets.only(top: 12, bottom: 18),

View File

@@ -228,6 +228,9 @@ class PlPlayerController {
/// 弹幕开关 /// 弹幕开关
Rx<bool> isOpenDanmu = false.obs; Rx<bool> isOpenDanmu = false.obs;
/// 弹幕权重
ValueNotifier<int> danmakuWeight = ValueNotifier(0);
// 关联弹幕控制器 // 关联弹幕控制器
DanmakuController? danmakuController; DanmakuController? danmakuController;
// 弹幕相关配置 // 弹幕相关配置
@@ -277,6 +280,8 @@ class PlPlayerController {
_videoType = videoType; _videoType = videoType;
isOpenDanmu.value = isOpenDanmu.value =
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false); setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: false);
danmakuWeight.value =
localCache.get(LocalCacheKey.danmakuWeight, defaultValue: 0);
blockTypes = blockTypes =
localCache.get(LocalCacheKey.danmakuBlockType, defaultValue: []); localCache.get(LocalCacheKey.danmakuBlockType, defaultValue: []);
showArea = localCache.get(LocalCacheKey.danmakuShowArea, defaultValue: 0.5); showArea = localCache.get(LocalCacheKey.danmakuShowArea, defaultValue: 0.5);
@@ -1121,6 +1126,7 @@ class PlPlayerController {
} }
void putDanmakuSettings() { void putDanmakuSettings() {
localCache.put(LocalCacheKey.danmakuWeight, danmakuWeight.value);
localCache.put(LocalCacheKey.danmakuBlockType, blockTypes); localCache.put(LocalCacheKey.danmakuBlockType, blockTypes);
localCache.put(LocalCacheKey.danmakuShowArea, showArea); localCache.put(LocalCacheKey.danmakuShowArea, showArea);
localCache.put(LocalCacheKey.danmakuOpacity, opacityVal); localCache.put(LocalCacheKey.danmakuOpacity, opacityVal);

View File

@@ -164,7 +164,8 @@ class LocalCacheKey {
wbiKeys = 'wbiKeys', wbiKeys = 'wbiKeys',
timeStamp = 'timeStamp', timeStamp = 'timeStamp',
// 弹幕相关设置 屏蔽类型 显示区域 透明度 字体大小 弹幕时间 描边粗细 // 弹幕相关设置 权重(云屏蔽) 屏蔽类型 显示区域 透明度 字体大小 弹幕时间 描边粗细
danmakuWeight = 'danmakuWeight',
danmakuBlockType = 'danmakuBlockType', danmakuBlockType = 'danmakuBlockType',
danmakuShowArea = 'danmakuShowArea', danmakuShowArea = 'danmakuShowArea',
danmakuOpacity = 'danmakuOpacity', danmakuOpacity = 'danmakuOpacity',