feat: 直播弹幕2

This commit is contained in:
guozhigq
2024-08-21 00:14:45 +08:00
parent 91856b5c21
commit 5304120909
4 changed files with 58 additions and 18 deletions

View File

@ -2,8 +2,9 @@ import 'package:pilipala/http/danmaku.dart';
import 'package:pilipala/models/danmaku/dm.pb.dart'; import 'package:pilipala/models/danmaku/dm.pb.dart';
class PlDanmakuController { class PlDanmakuController {
PlDanmakuController(this.cid); PlDanmakuController(this.cid, this.type);
final int cid; final int cid;
final String type;
Map<int, List<DanmakuElem>> dmSegMap = {}; Map<int, List<DanmakuElem>> dmSegMap = {};
// 已请求的段落标记 // 已请求的段落标记
List<bool> requestedSeg = []; List<bool> requestedSeg = [];

View File

@ -12,11 +12,15 @@ import 'package:pilipala/utils/storage.dart';
class PlDanmaku extends StatefulWidget { class PlDanmaku extends StatefulWidget {
final int cid; final int cid;
final PlPlayerController playerController; final PlPlayerController playerController;
final String type;
final Function(DanmakuController)? createdController;
const PlDanmaku({ const PlDanmaku({
super.key, super.key,
required this.cid, required this.cid,
required this.playerController, required this.playerController,
this.type = 'video',
this.createdController,
}); });
@override @override
@ -43,9 +47,9 @@ 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.type);
if (mounted) { playerController = widget.playerController;
playerController = widget.playerController; if (mounted && widget.type == 'video') {
if (enableShowDanmaku || playerController.isOpenDanmu.value) { if (enableShowDanmaku || playerController.isOpenDanmu.value) {
_plDanmakuController.initiate( _plDanmakuController.initiate(
playerController.duration.value.inMilliseconds, playerController.duration.value.inMilliseconds,
@ -55,13 +59,15 @@ class _PlDanmakuState extends State<PlDanmaku> {
..addStatusLister(playerListener) ..addStatusLister(playerListener)
..addPositionListener(videoPositionListen); ..addPositionListener(videoPositionListen);
} }
playerController.isOpenDanmu.listen((p0) { if (widget.type == 'video') {
if (p0 && !_plDanmakuController.initiated) { playerController.isOpenDanmu.listen((p0) {
_plDanmakuController.initiate( if (p0 && !_plDanmakuController.initiated) {
playerController.duration.value.inMilliseconds, _plDanmakuController.initiate(
playerController.position.value.inMilliseconds); playerController.duration.value.inMilliseconds,
} playerController.position.value.inMilliseconds);
}); }
});
}
blockTypes = playerController.blockTypes; blockTypes = playerController.blockTypes;
showArea = playerController.showArea; showArea = playerController.showArea;
opacityVal = playerController.opacityVal; opacityVal = playerController.opacityVal;
@ -128,6 +134,7 @@ class _PlDanmakuState extends State<PlDanmaku> {
child: DanmakuView( child: DanmakuView(
createdController: (DanmakuController e) async { createdController: (DanmakuController e) async {
playerController.danmakuController = _controller = e; playerController.danmakuController = _controller = e;
widget.createdController?.call(e);
}, },
option: DanmakuOption( option: DanmakuOption(
fontSize: 15 * fontSizeVal, fontSize: 15 * fontSizeVal,
@ -136,8 +143,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

@ -1,7 +1,9 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:ui';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:ns_danmaku/ns_danmaku.dart';
import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/init.dart'; import 'package:pilipala/http/init.dart';
import 'package:pilipala/http/live.dart'; import 'package:pilipala/http/live.dart';
@ -37,6 +39,7 @@ class LiveRoomController extends GetxController {
String token = ''; String token = '';
// 弹幕消息列表 // 弹幕消息列表
RxList<LiveMessageModel> messageList = <LiveMessageModel>[].obs; RxList<LiveMessageModel> messageList = <LiveMessageModel>[].obs;
DanmakuController? danmakuController;
@override @override
void onInit() { void onInit() {
@ -172,9 +175,28 @@ class LiveRoomController extends GetxController {
final List<LiveMessageModel>? liveMsg = final List<LiveMessageModel>? liveMsg =
LiveUtils.decodeMessage(message); LiveUtils.decodeMessage(message);
if (liveMsg != null) { if (liveMsg != null) {
messageList.addAll(liveMsg // 过滤出聊天消息
.where((msg) => msg.type == LiveMessageType.chat) var chatMessages =
.toList()); liveMsg.where((msg) => msg.type == LiveMessageType.chat).toList();
// 添加到 messageList
messageList.addAll(chatMessages);
// 将 chatMessages 转换为 danmakuItems 列表
List<DanmakuItem> danmakuItems = chatMessages.map<DanmakuItem>((e) {
return DanmakuItem(
e.message ?? '',
color: Color.fromARGB(
255,
e.color.r,
e.color.g,
e.color.b,
),
);
}).toList();
// 添加到 danmakuController
danmakuController?.addItems(danmakuItems);
} }
}, },
onErrorCb: (e) { onErrorCb: (e) {

View File

@ -7,6 +7,7 @@ import 'package:flutter/rendering.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/models/live/message.dart'; import 'package:pilipala/models/live/message.dart';
import 'package:pilipala/pages/danmaku/index.dart';
import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/index.dart';
import 'controller.dart'; import 'controller.dart';
@ -22,7 +23,7 @@ class LiveRoomPage extends StatefulWidget {
class _LiveRoomPageState extends State<LiveRoomPage> class _LiveRoomPageState extends State<LiveRoomPage>
with TickerProviderStateMixin { with TickerProviderStateMixin {
final LiveRoomController _liveRoomController = Get.put(LiveRoomController()); final LiveRoomController _liveRoomController = Get.put(LiveRoomController());
PlPlayerController? plPlayerController; late PlPlayerController plPlayerController;
late Future? _futureBuilder; late Future? _futureBuilder;
late Future? _futureBuilderFuture; late Future? _futureBuilderFuture;
@ -32,6 +33,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
late AnimationController fabAnimationCtr; late AnimationController fabAnimationCtr;
bool _shouldAutoScroll = true; bool _shouldAutoScroll = true;
final int roomId = int.parse(Get.parameters['roomid']!);
@override @override
void initState() { void initState() {
@ -110,8 +112,9 @@ class _LiveRoomPageState extends State<LiveRoomPage>
future: _futureBuilderFuture, future: _futureBuilderFuture,
builder: (BuildContext context, AsyncSnapshot snapshot) { builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData && snapshot.data['status']) { if (snapshot.hasData && snapshot.data['status']) {
plPlayerController = _liveRoomController.plPlayerController;
return PLVideoPlayer( return PLVideoPlayer(
controller: plPlayerController!, controller: plPlayerController,
bottomControl: BottomControl( bottomControl: BottomControl(
controller: plPlayerController, controller: plPlayerController,
liveRoomCtr: _liveRoomController, liveRoomCtr: _liveRoomController,
@ -122,6 +125,14 @@ class _LiveRoomPageState extends State<LiveRoomPage>
}); });
}, },
), ),
danmuWidget: PlDanmaku(
cid: roomId,
playerController: plPlayerController,
type: 'live',
createdController: (e) {
_liveRoomController.danmakuController = e;
},
),
); );
} else { } else {
return const SizedBox(); return const SizedBox();