mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: 新增弹幕按等级云屏蔽功能
This commit is contained in:
@@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
Reference in New Issue
Block a user