mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-01 00:28:18 +08:00
197 lines
5.5 KiB
Dart
197 lines
5.5 KiB
Dart
import 'dart:async';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:hive/hive.dart';
|
|
import 'package:pilipala/http/constants.dart';
|
|
import 'package:pilipala/http/video.dart';
|
|
import 'package:pilipala/models/common/reply_type.dart';
|
|
import 'package:pilipala/models/video/play/quality.dart';
|
|
import 'package:pilipala/models/video/play/url.dart';
|
|
import 'package:pilipala/models/video/reply/item.dart';
|
|
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
|
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
|
import 'package:pilipala/utils/storage.dart';
|
|
|
|
class VideoDetailController extends GetxController
|
|
with GetSingleTickerProviderStateMixin {
|
|
int tabInitialIndex = 0;
|
|
TabController? tabCtr;
|
|
// tabs
|
|
RxList<String> tabs = <String>['简介', '评论'].obs;
|
|
|
|
// 视频aid
|
|
String bvid = Get.parameters['bvid']!;
|
|
int cid = int.parse(Get.parameters['cid']!);
|
|
late PlayUrlModel data;
|
|
// 当前画质
|
|
late VideoQuality currentVideoQa;
|
|
// 当前音质
|
|
late AudioQuality currentAudioQa;
|
|
|
|
// 是否预渲染 骨架屏
|
|
bool preRender = false;
|
|
|
|
// 视频详情 上个页面传入
|
|
Map videoItem = {};
|
|
|
|
// 请求状态
|
|
RxBool isLoading = false.obs;
|
|
|
|
String heroTag = '';
|
|
|
|
int oid = 0;
|
|
// 评论id 请求楼中楼评论使用
|
|
int fRpid = 0;
|
|
|
|
ReplyItemModel? firstFloor;
|
|
final scaffoldKey = GlobalKey<ScaffoldState>();
|
|
Timer? timer;
|
|
RxString bgCover = ''.obs;
|
|
Box user = GStrorage.user;
|
|
Box localCache = GStrorage.localCache;
|
|
PlPlayerController plPlayerController = PlPlayerController();
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
if (Get.arguments.isNotEmpty) {
|
|
if (Get.arguments.containsKey('videoItem')) {
|
|
preRender = true;
|
|
var args = Get.arguments['videoItem'];
|
|
if (args.pic != null && args.pic != '') {
|
|
videoItem['pic'] = args.pic;
|
|
bgCover.value = args.pic;
|
|
}
|
|
}
|
|
if (Get.arguments.containsKey('pic')) {
|
|
videoItem['pic'] = Get.arguments['pic'];
|
|
bgCover.value = Get.arguments['pic'];
|
|
}
|
|
heroTag = Get.arguments['heroTag'];
|
|
}
|
|
tabCtr = TabController(length: 2, vsync: this);
|
|
queryVideoUrl();
|
|
}
|
|
|
|
showReplyReplyPanel() {
|
|
PersistentBottomSheetController<void>? ctr =
|
|
scaffoldKey.currentState?.showBottomSheet<void>((BuildContext context) {
|
|
return VideoReplyReplyPanel(
|
|
oid: oid,
|
|
rpid: fRpid,
|
|
closePanel: () => {
|
|
fRpid = 0,
|
|
},
|
|
firstFloor: firstFloor,
|
|
replyType: ReplyType.video,
|
|
source: 'videoDetail',
|
|
);
|
|
});
|
|
ctr?.closed.then((value) {
|
|
fRpid = 0;
|
|
});
|
|
}
|
|
|
|
/// 更新画质、音质
|
|
/// TODO 继续进度播放
|
|
updatePlayer() {
|
|
Duration position = plPlayerController.position.value;
|
|
plPlayerController.removeListeners();
|
|
plPlayerController.isBuffering.value = false;
|
|
plPlayerController.buffered.value = Duration.zero;
|
|
|
|
/// 暂不匹配解码规则
|
|
|
|
/// 根据currentVideoQa 重新设置videoUrl
|
|
VideoItem firstVideo =
|
|
data.dash!.video!.firstWhere((i) => i.id == currentVideoQa.code);
|
|
String videoUrl = firstVideo.baseUrl!;
|
|
|
|
/// 根据currentAudioQa 重新设置audioUrl
|
|
AudioItem firstAudio =
|
|
data.dash!.audio!.firstWhere((i) => i.id == currentAudioQa.code);
|
|
String audioUrl = firstAudio.baseUrl ?? '';
|
|
|
|
playerInit(videoUrl, audioUrl, defaultST: position);
|
|
}
|
|
|
|
playerInit(source, audioSource,
|
|
{Duration defaultST = Duration.zero, int duration = 0}) async {
|
|
plPlayerController.setDataSource(
|
|
DataSource(
|
|
videoSource: source,
|
|
audioSource: audioSource,
|
|
type: DataSourceType.network,
|
|
httpHeaders: {
|
|
'user-agent':
|
|
'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_3_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Safari/605.1.15',
|
|
'referer': HttpString.baseUrl
|
|
},
|
|
),
|
|
// 硬解
|
|
enableHA: true,
|
|
autoplay: true,
|
|
seekTo: defaultST,
|
|
duration: Duration(milliseconds: duration),
|
|
);
|
|
}
|
|
|
|
// 视频链接
|
|
queryVideoUrl() async {
|
|
var result = await VideoHttp.videoUrl(cid: cid, bvid: bvid);
|
|
if (result['status']) {
|
|
data = result['data'];
|
|
|
|
/// 优先顺序 省流模式 -> 设置中指定质量 -> 当前可选的最高质量
|
|
VideoItem firstVideo = data.dash!.video!.first;
|
|
String videoUrl = firstVideo.baseUrl!;
|
|
//
|
|
currentVideoQa = VideoQualityCode.fromCode(firstVideo.id!)!;
|
|
|
|
/// 优先顺序 设置中指定质量 -> 当前可选的最高质量
|
|
AudioItem firstAudio =
|
|
data.dash!.audio!.isNotEmpty ? data.dash!.audio!.first : AudioItem();
|
|
String audioUrl = firstAudio.baseUrl ?? '';
|
|
//
|
|
currentAudioQa = AudioQualityCode.fromCode(firstAudio.id!)!;
|
|
|
|
playerInit(
|
|
videoUrl,
|
|
audioUrl,
|
|
defaultST: Duration(milliseconds: data.lastPlayTime!),
|
|
duration: data.timeLength ?? 0,
|
|
);
|
|
}
|
|
}
|
|
|
|
void loopHeartBeat() {
|
|
timer = Timer.periodic(const Duration(seconds: 5), (timer) {
|
|
markHeartBeat();
|
|
});
|
|
}
|
|
|
|
void markHeartBeat() async {
|
|
if (user.get(UserBoxKey.userMid) == null) {
|
|
return;
|
|
}
|
|
if (localCache.get(LocalCacheKey.historyStatus) == true) {
|
|
return;
|
|
}
|
|
Duration progress = plPlayerController.position.value;
|
|
await VideoHttp.heartBeat(
|
|
bvid: bvid,
|
|
cid: cid,
|
|
progress: progress.inSeconds,
|
|
);
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
markHeartBeat();
|
|
if (timer != null && timer!.isActive) {
|
|
timer!.cancel();
|
|
}
|
|
super.onClose();
|
|
}
|
|
}
|