mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-07-14 21:30:15 +08:00
tweak: danmaku (#1756)
* fix: danmaku like * opt: danmaku merge * remove: showSpecialDanmaku
This commit is contained in:
committed by
GitHub
parent
0f8da1999a
commit
62bb605ee8
@@ -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<int, List<DanmakuElem>> dmSegMap = {};
|
||||
final Map<int, List<DanmakuElem>> _dmSegMap = {};
|
||||
// 已请求的段落标记
|
||||
late final Set<int> requestedSeg = {};
|
||||
late final Set<int> _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<void> 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<DanmakuElem> elems) {
|
||||
if (elems.isEmpty) return;
|
||||
late final Map<String, int> 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<String, DanmakuElem>();
|
||||
|
||||
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<DanmakuElem>? 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<void> _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();
|
||||
|
||||
@@ -34,7 +34,7 @@ class PlDanmaku extends StatefulWidget {
|
||||
class _PlDanmakuState extends State<PlDanmaku> {
|
||||
PlPlayerController get playerController => widget.playerController;
|
||||
|
||||
late PlDanmakuController _plDanmakuController;
|
||||
late final PlDanmakuController _plDanmakuController;
|
||||
DanmakuController<DanmakuExtra>? _controller;
|
||||
int latestAddedPosition = -1;
|
||||
|
||||
@@ -90,6 +90,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
|
||||
}
|
||||
}
|
||||
|
||||
@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<PlDanmaku> {
|
||||
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(),
|
||||
|
||||
@@ -536,13 +536,6 @@ List<SettingsModel> 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: '合并弹幕',
|
||||
|
||||
@@ -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<T extends StatefulWidget> on State<T> {
|
||||
/// 弹幕功能
|
||||
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<T extends StatefulWidget> on State<T> {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user