mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-01 00:28:18 +08:00
opt: merge danmaku in loop (#813)
This commit is contained in:
committed by
GitHub
parent
a49caa871d
commit
07d2b3b464
@@ -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/grpc/grpc_repo.dart';
|
||||||
import 'package:PiliPlus/http/api.dart';
|
import 'package:PiliPlus/http/api.dart';
|
||||||
import 'package:PiliPlus/http/init.dart';
|
import 'package:PiliPlus/http/init.dart';
|
||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
class DanmakuHttp {
|
class DanmakuHttp {
|
||||||
// 获取视频弹幕
|
// 获取视频弹幕
|
||||||
static Future queryDanmaku({
|
static Future<LoadingState<DmSegMobileReply>> queryDanmaku({
|
||||||
required int cid,
|
required int cid,
|
||||||
required int segmentIndex,
|
required int segmentIndex,
|
||||||
required bool mergeDanmaku,
|
|
||||||
int queryCount = 1,
|
int queryCount = 1,
|
||||||
}) async {
|
}) async {
|
||||||
// 构建参数对象
|
// 构建参数对象
|
||||||
@@ -18,34 +18,18 @@ class DanmakuHttp {
|
|||||||
await GrpcRepo.dmSegMobile(cid: cid, segmentIndex: segmentIndex);
|
await GrpcRepo.dmSegMobile(cid: cid, segmentIndex: segmentIndex);
|
||||||
if (!response['status']) {
|
if (!response['status']) {
|
||||||
if (queryCount >= 3) {
|
if (queryCount >= 3) {
|
||||||
return {'status': false};
|
return const Error('');
|
||||||
} else {
|
} else {
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(seconds: 1));
|
||||||
return await queryDanmaku(
|
return await queryDanmaku(
|
||||||
cid: cid,
|
cid: cid,
|
||||||
segmentIndex: segmentIndex,
|
segmentIndex: segmentIndex,
|
||||||
mergeDanmaku: mergeDanmaku,
|
|
||||||
queryCount: ++queryCount,
|
queryCount: ++queryCount,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DmSegMobileReply data = response['data'];
|
DmSegMobileReply data = response['data'];
|
||||||
if (mergeDanmaku && data.elems.isNotEmpty) {
|
return LoadingState.success(data);
|
||||||
final Map counts = <String, int>{};
|
|
||||||
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};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future shootDanmaku({
|
static Future shootDanmaku({
|
||||||
|
|||||||
@@ -6,15 +6,16 @@ class PlDanmakuController {
|
|||||||
PlDanmakuController(
|
PlDanmakuController(
|
||||||
this.cid,
|
this.cid,
|
||||||
this.plPlayerController,
|
this.plPlayerController,
|
||||||
);
|
) : mergeDanmaku = plPlayerController.mergeDanmaku;
|
||||||
final int cid;
|
final int cid;
|
||||||
final PlPlayerController plPlayerController;
|
final PlPlayerController plPlayerController;
|
||||||
|
final bool mergeDanmaku;
|
||||||
|
|
||||||
Map<int, List<DanmakuElem>> dmSegMap = {};
|
Map<int, List<DanmakuElem>> dmSegMap = {};
|
||||||
// 已请求的段落标记
|
// 已请求的段落标记
|
||||||
Map requestedSeg = {};
|
Set<int> requestedSeg = {};
|
||||||
|
|
||||||
static int segmentLength = 60 * 6 * 1000;
|
static const int segmentLength = 60 * 6 * 1000;
|
||||||
|
|
||||||
void dispose() {
|
void dispose() {
|
||||||
dmSegMap.clear();
|
dmSegMap.clear();
|
||||||
@@ -26,36 +27,48 @@ class PlDanmakuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> queryDanmaku(int segmentIndex) async {
|
Future<void> queryDanmaku(int segmentIndex) async {
|
||||||
if (requestedSeg[segmentIndex] == true) {
|
if (requestedSeg.contains(segmentIndex)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
requestedSeg[segmentIndex] = true;
|
requestedSeg.add(segmentIndex);
|
||||||
final Map result = await DanmakuHttp.queryDanmaku(
|
final result = await DanmakuHttp.queryDanmaku(
|
||||||
cid: cid,
|
cid: cid,
|
||||||
segmentIndex: segmentIndex + 1,
|
segmentIndex: segmentIndex + 1,
|
||||||
mergeDanmaku: plPlayerController.mergeDanmaku,
|
|
||||||
);
|
);
|
||||||
if (result['status']) {
|
|
||||||
if (result['data'].elems.isNotEmpty) {
|
if (result.isSuccess) {
|
||||||
for (DanmakuElem element in result['data'].elems) {
|
final data = result.data;
|
||||||
if (element.mode == 7 && !plPlayerController.showSpecialDanmaku) {
|
if (data.elems.isNotEmpty) {
|
||||||
continue;
|
final Map<String, int> 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秒存储一次
|
int pos = element.progress ~/ 100; //每0.1秒存储一次
|
||||||
if (dmSegMap[pos] == null) {
|
(dmSegMap[pos] ??= []).add(element);
|
||||||
dmSegMap[pos] = [];
|
|
||||||
}
|
|
||||||
dmSegMap[pos]!.add(element);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
requestedSeg[segmentIndex] = false;
|
requestedSeg.remove(segmentIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DanmakuElem>? getCurrentDanmaku(int progress) {
|
List<DanmakuElem>? getCurrentDanmaku(int progress) {
|
||||||
int segmentIndex = calcSegment(progress);
|
int segmentIndex = calcSegment(progress);
|
||||||
if (requestedSeg[segmentIndex] != true) {
|
if (!requestedSeg.contains(segmentIndex)) {
|
||||||
queryDanmaku(segmentIndex);
|
queryDanmaku(segmentIndex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1264,13 +1264,13 @@ class HeaderControlState extends State<HeaderControl> {
|
|||||||
/// 弹幕功能
|
/// 弹幕功能
|
||||||
void showSetDanmaku() {
|
void showSetDanmaku() {
|
||||||
// 屏蔽类型
|
// 屏蔽类型
|
||||||
const List<Map<String, dynamic>> blockTypesList = [
|
const List<({int value, String label})> blockTypesList = [
|
||||||
{'value': 5, 'label': '顶部'},
|
(value: 5, label: '顶部'),
|
||||||
{'value': 2, 'label': '滚动'},
|
(value: 2, label: '滚动'),
|
||||||
{'value': 4, 'label': '底部'},
|
(value: 4, label: '底部'),
|
||||||
{'value': 6, 'label': '彩色'},
|
(value: 6, label: '彩色'),
|
||||||
];
|
];
|
||||||
final List blockTypes = widget.controller.blockTypes;
|
final blockTypes = widget.controller.blockTypes;
|
||||||
// 智能云屏蔽
|
// 智能云屏蔽
|
||||||
int danmakuWeight = widget.controller.danmakuWeight;
|
int danmakuWeight = widget.controller.danmakuWeight;
|
||||||
// 显示区域
|
// 显示区域
|
||||||
@@ -1501,16 +1501,14 @@ class HeaderControlState extends State<HeaderControl> {
|
|||||||
padding: const EdgeInsets.only(top: 12),
|
padding: const EdgeInsets.only(top: 12),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
for (final Map<String, dynamic> i
|
for (final (value: value, label: label)
|
||||||
in blockTypesList) ...[
|
in blockTypesList) ...[
|
||||||
ActionRowLineItem(
|
ActionRowLineItem(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
final bool isChoose =
|
if (blockTypes.contains(value)) {
|
||||||
blockTypes.contains(i['value']);
|
blockTypes.remove(value);
|
||||||
if (isChoose) {
|
|
||||||
blockTypes.remove(i['value']);
|
|
||||||
} else {
|
} else {
|
||||||
blockTypes.add(i['value']);
|
blockTypes.add(value);
|
||||||
}
|
}
|
||||||
widget.controller
|
widget.controller
|
||||||
..blockTypes = blockTypes
|
..blockTypes = blockTypes
|
||||||
@@ -1527,8 +1525,8 @@ class HeaderControlState extends State<HeaderControl> {
|
|||||||
);
|
);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
},
|
},
|
||||||
text: i['label'],
|
text: label,
|
||||||
selectStatus: blockTypes.contains(i['value']),
|
selectStatus: blockTypes.contains(value),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ class PlPlayerController {
|
|||||||
bool showDanmaku = true;
|
bool showDanmaku = true;
|
||||||
late final mergeDanmaku = GStorage.mergeDanmaku;
|
late final mergeDanmaku = GStorage.mergeDanmaku;
|
||||||
// 弹幕相关配置
|
// 弹幕相关配置
|
||||||
late List blockTypes;
|
late Set<int> blockTypes;
|
||||||
late double showArea;
|
late double showArea;
|
||||||
late double opacity;
|
late double opacity;
|
||||||
late double fontSize;
|
late double fontSize;
|
||||||
@@ -434,7 +434,11 @@ class PlPlayerController {
|
|||||||
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: true);
|
setting.get(SettingBoxKey.enableShowDanmaku, defaultValue: true);
|
||||||
danmakuWeight = setting.get(SettingBoxKey.danmakuWeight, defaultValue: 0);
|
danmakuWeight = setting.get(SettingBoxKey.danmakuWeight, defaultValue: 0);
|
||||||
filters = GStorage.danmakuFilterRule;
|
filters = GStorage.danmakuFilterRule;
|
||||||
blockTypes = setting.get(SettingBoxKey.danmakuBlockType, defaultValue: []);
|
blockTypes =
|
||||||
|
(setting.get(SettingBoxKey.danmakuBlockType, defaultValue: <int>[])
|
||||||
|
as Iterable)
|
||||||
|
.cast<int>()
|
||||||
|
.toSet();
|
||||||
showArea = setting.get(SettingBoxKey.danmakuShowArea, defaultValue: 0.5);
|
showArea = setting.get(SettingBoxKey.danmakuShowArea, defaultValue: 0.5);
|
||||||
// 不透明度
|
// 不透明度
|
||||||
opacity = setting.get(SettingBoxKey.danmakuOpacity, defaultValue: 1.0);
|
opacity = setting.get(SettingBoxKey.danmakuOpacity, defaultValue: 1.0);
|
||||||
@@ -1484,7 +1488,7 @@ class PlPlayerController {
|
|||||||
void putDanmakuSettings() {
|
void putDanmakuSettings() {
|
||||||
setting
|
setting
|
||||||
..put(SettingBoxKey.danmakuWeight, danmakuWeight)
|
..put(SettingBoxKey.danmakuWeight, danmakuWeight)
|
||||||
..put(SettingBoxKey.danmakuBlockType, blockTypes)
|
..put(SettingBoxKey.danmakuBlockType, blockTypes.toList())
|
||||||
..put(SettingBoxKey.danmakuShowArea, showArea)
|
..put(SettingBoxKey.danmakuShowArea, showArea)
|
||||||
..put(SettingBoxKey.danmakuOpacity, opacity)
|
..put(SettingBoxKey.danmakuOpacity, opacity)
|
||||||
..put(SettingBoxKey.danmakuFontScale, fontSize)
|
..put(SettingBoxKey.danmakuFontScale, fontSize)
|
||||||
|
|||||||
Reference in New Issue
Block a user