mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-25 04:45:54 +08:00
@@ -11,7 +11,6 @@ import 'package:PiliPlus/http/constants.dart';
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/sponsor_block.dart';
|
||||
import 'package:PiliPlus/http/ua_type.dart';
|
||||
import 'package:PiliPlus/http/user.dart';
|
||||
import 'package:PiliPlus/http/video.dart';
|
||||
@@ -21,7 +20,6 @@ import 'package:PiliPlus/models/common/sponsor_block/action_type.dart';
|
||||
import 'package:PiliPlus/models/common/sponsor_block/post_segment_model.dart';
|
||||
import 'package:PiliPlus/models/common/sponsor_block/segment_model.dart';
|
||||
import 'package:PiliPlus/models/common/sponsor_block/segment_type.dart';
|
||||
import 'package:PiliPlus/models/common/sponsor_block/skip_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
||||
import 'package:PiliPlus/models/common/video/source_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/subtitle_pref_type.dart';
|
||||
@@ -32,7 +30,6 @@ import 'package:PiliPlus/models/video/play/url.dart';
|
||||
import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart';
|
||||
import 'package:PiliPlus/models_new/media_list/media_list.dart';
|
||||
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart';
|
||||
import 'package:PiliPlus/models_new/sponsor_block/segment_item.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/data.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/episode.dart' as ugc;
|
||||
import 'package:PiliPlus/models_new/video/video_detail/page.dart';
|
||||
@@ -42,6 +39,7 @@ import 'package:PiliPlus/models_new/video/video_stein_edgeinfo/data.dart';
|
||||
import 'package:PiliPlus/pages/audio/view.dart';
|
||||
import 'package:PiliPlus/pages/common/publish/publish_route.dart';
|
||||
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
|
||||
import 'package:PiliPlus/pages/sponsor_block/block_mixin.dart';
|
||||
import 'package:PiliPlus/pages/video/download_panel/view.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/pgc/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
|
||||
@@ -56,7 +54,6 @@ import 'package:PiliPlus/plugin/pl_player/models/heart_beat_type.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
||||
import 'package:PiliPlus/services/download/download_service.dart';
|
||||
import 'package:PiliPlus/utils/accounts.dart';
|
||||
import 'package:PiliPlus/utils/duration_utils.dart';
|
||||
import 'package:PiliPlus/utils/extension/context_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||
import 'package:PiliPlus/utils/extension/num_ext.dart';
|
||||
@@ -67,7 +64,6 @@ import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:PiliPlus/utils/video_utils.dart';
|
||||
import 'package:easy_debounce/easy_throttle.dart';
|
||||
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -75,11 +71,10 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
|
||||
class VideoDetailController extends GetxController
|
||||
with GetTickerProviderStateMixin {
|
||||
with GetTickerProviderStateMixin, BlockMixin {
|
||||
/// 路由传参
|
||||
late final Map args;
|
||||
late String bvid;
|
||||
@@ -93,6 +88,7 @@ class VideoDetailController extends GetxController
|
||||
|
||||
// 视频类型 默认投稿视频
|
||||
late final VideoType videoType;
|
||||
@override
|
||||
late final isUgc = videoType == VideoType.ugc;
|
||||
VideoType? _actualVideoType;
|
||||
|
||||
@@ -118,7 +114,7 @@ class VideoDetailController extends GetxController
|
||||
late VideoDecodeFormatType currentDecodeFormats;
|
||||
|
||||
// 是否开始自动播放 存在多p的情况下,第二p需要为true
|
||||
final RxBool autoPlay = Pref.autoPlayEnable.obs;
|
||||
final RxBool _autoPlay = Pref.autoPlayEnable.obs;
|
||||
|
||||
final videoPlayerKey = GlobalKey();
|
||||
final childKey = GlobalKey<ScaffoldState>();
|
||||
@@ -165,7 +161,6 @@ class VideoDetailController extends GetxController
|
||||
late final RxInt seasonIndex = 0.obs;
|
||||
|
||||
PlayerStatus? playerStatus;
|
||||
StreamSubscription<Duration>? positionSubscription;
|
||||
|
||||
late final scrollKey = GlobalKey<ExtendedNestedScrollViewState>();
|
||||
late final RxBool isVertical = false.obs;
|
||||
@@ -487,459 +482,32 @@ class VideoDetailController extends GetxController
|
||||
bool get showVideoSheet =>
|
||||
(!horizontalScreen && !isPortrait) || plPlayerController.isDesktopPip;
|
||||
|
||||
late final _isBlock = isUgc || !plPlayerController.enablePgcSkip;
|
||||
int? _lastPos;
|
||||
late final List<PostSegmentModel> postList = [];
|
||||
late final List<SegmentModel> segmentList = <SegmentModel>[];
|
||||
late final RxList<Segment> segmentProgressList = <Segment>[].obs;
|
||||
@override
|
||||
late final RxString videoLabel = ''.obs;
|
||||
@override
|
||||
int? get timeLength => data.timeLength;
|
||||
@override
|
||||
BlockConfigMixin get blockConfig => plPlayerController;
|
||||
@override
|
||||
Player? get player => plPlayerController.videoPlayerController;
|
||||
@override
|
||||
bool get isFullScreen => plPlayerController.isFullScreen.value;
|
||||
@override
|
||||
bool get autoPlay => _autoPlay.value;
|
||||
set autoPlay(bool value) => _autoPlay.value = value;
|
||||
@override
|
||||
bool get preInitPlayer => plPlayerController.preInitPlayer;
|
||||
@override
|
||||
int get currPosInMilliseconds =>
|
||||
defaultST?.inMilliseconds ??
|
||||
plPlayerController.position.value.inMilliseconds;
|
||||
@override
|
||||
Future<void> seekTo(Duration duration, {required bool isSeek}) =>
|
||||
plPlayerController.seekTo(duration, isSeek: isSeek);
|
||||
|
||||
Color _getColor(SegmentType segment) =>
|
||||
plPlayerController.blockColor[segment.index];
|
||||
late RxString videoLabel = ''.obs;
|
||||
|
||||
Timer? skipTimer;
|
||||
late final listKey = GlobalKey<AnimatedListState>();
|
||||
late final List listData = [];
|
||||
|
||||
void _vote(String uuid, int type) {
|
||||
SponsorBlock.voteOnSponsorTime(
|
||||
uuid: uuid,
|
||||
type: type,
|
||||
).then((i) => SmartDialog.showToast(i.isSuccess ? '投票成功' : '投票失败: $i'));
|
||||
}
|
||||
|
||||
void _showCategoryDialog(BuildContext context, SegmentModel segment) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: SegmentType.values
|
||||
.map(
|
||||
(item) => ListTile(
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Get.back();
|
||||
SponsorBlock.voteOnSponsorTime(
|
||||
uuid: segment.UUID,
|
||||
category: item,
|
||||
).then((i) {
|
||||
SmartDialog.showToast(
|
||||
'类别更改${i.isSuccess ? '成功' : '失败: $i'}',
|
||||
);
|
||||
});
|
||||
},
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Container(
|
||||
height: 10,
|
||||
width: 10,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _getColor(item),
|
||||
),
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, height: 1),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' ${item.title}',
|
||||
style: const TextStyle(fontSize: 14, height: 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showVoteDialog(BuildContext context, SegmentModel segment) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'赞成票',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_vote(segment.UUID, 1);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'反对票',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_vote(segment.UUID, 0);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'更改类别',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_showCategoryDialog(context, segment);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void showSBDetail(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
|
||||
content: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: segmentList
|
||||
.map(
|
||||
(item) => ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
if (_isBlock) {
|
||||
_showVoteDialog(context, item);
|
||||
}
|
||||
},
|
||||
dense: true,
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
alignment: PlaceholderAlignment.middle,
|
||||
child: Container(
|
||||
height: 10,
|
||||
width: 10,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: _getColor(item.segmentType),
|
||||
),
|
||||
),
|
||||
style: const TextStyle(fontSize: 14, height: 1),
|
||||
),
|
||||
TextSpan(
|
||||
text: ' ${item.segmentType.title}',
|
||||
style: const TextStyle(fontSize: 14, height: 1),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
contentPadding: const EdgeInsets.only(left: 16, right: 8),
|
||||
subtitle: Text(
|
||||
'${DurationUtils.formatDuration(item.segment.first / 1000)} 至 ${DurationUtils.formatDuration(item.segment.second / 1000)}',
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
trailing: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
item.skipType.label,
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
if (item.segment.second != 0)
|
||||
SizedBox(
|
||||
width: 36,
|
||||
height: 36,
|
||||
child: IconButton(
|
||||
tooltip: item.skipType == SkipType.showOnly
|
||||
? '跳至此片段'
|
||||
: '跳过此片段',
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
onSkip(
|
||||
item,
|
||||
isSkip: item.skipType != SkipType.showOnly,
|
||||
isSeek: false,
|
||||
);
|
||||
},
|
||||
style: IconButton.styleFrom(
|
||||
padding: EdgeInsets.zero,
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
icon: Icon(
|
||||
item.skipType == SkipType.showOnly
|
||||
? Icons.my_location
|
||||
: MdiIcons.debugStepOver,
|
||||
size: 18,
|
||||
color: Theme.of(
|
||||
context,
|
||||
).colorScheme.onSurface.withValues(alpha: 0.7),
|
||||
),
|
||||
),
|
||||
)
|
||||
else
|
||||
const SizedBox(width: 10),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showBlockToast(String msg) {
|
||||
SmartDialog.showToast(
|
||||
msg,
|
||||
alignment: plPlayerController.isFullScreen.value
|
||||
? const Alignment(0, 0.7)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _querySponsorBlock() async {
|
||||
positionSubscription?.cancel();
|
||||
positionSubscription = null;
|
||||
videoLabel.value = '';
|
||||
segmentList.clear();
|
||||
segmentProgressList.clear();
|
||||
|
||||
final result = await SponsorBlock.getSkipSegments(
|
||||
bvid: bvid,
|
||||
cid: cid.value,
|
||||
);
|
||||
switch (result) {
|
||||
case Success<List<SegmentItemModel>>(:final response):
|
||||
handleSBData(response);
|
||||
case Error(:final code) when code != 404:
|
||||
if (kDebugMode) {
|
||||
result.toast();
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleSBData(List<SegmentItemModel> list) async {
|
||||
if (list.isNotEmpty) {
|
||||
try {
|
||||
Future? future;
|
||||
final duration = list.first.videoDuration ?? data.timeLength!;
|
||||
// segmentList
|
||||
segmentList.addAll(
|
||||
list
|
||||
.where(
|
||||
(item) =>
|
||||
plPlayerController.enableList.contains(item.category) &&
|
||||
item.segment[1] >= item.segment[0],
|
||||
)
|
||||
.map(
|
||||
(item) {
|
||||
final segmentType = SegmentType.values.byName(item.category);
|
||||
if (item.segment[0] == 0 && item.segment[1] == 0) {
|
||||
videoLabel.value +=
|
||||
'${videoLabel.value.isNotEmpty ? '/' : ''}${segmentType.title}';
|
||||
}
|
||||
SkipType skipType;
|
||||
if (_isBlock) {
|
||||
skipType = plPlayerController
|
||||
.blockSettings[segmentType.index]
|
||||
.second;
|
||||
if (skipType != SkipType.showOnly) {
|
||||
if (item.segment[1] == item.segment[0] ||
|
||||
item.segment[1] - item.segment[0] <
|
||||
plPlayerController.blockLimit) {
|
||||
skipType = SkipType.showOnly;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
skipType = Pref.pgcSkipType;
|
||||
}
|
||||
|
||||
final segmentModel = SegmentModel(
|
||||
UUID: item.uuid,
|
||||
segmentType: segmentType,
|
||||
segment: Pair(
|
||||
first: item.segment[0],
|
||||
second: item.segment[1],
|
||||
),
|
||||
skipType: skipType,
|
||||
);
|
||||
|
||||
if (positionSubscription == null &&
|
||||
autoPlay.value &&
|
||||
plPlayerController.videoPlayerController != null) {
|
||||
final currPost =
|
||||
defaultST?.inMilliseconds ??
|
||||
plPlayerController.position.value.inMilliseconds;
|
||||
|
||||
if (currPost >= segmentModel.segment.first &&
|
||||
currPost < segmentModel.segment.second) {
|
||||
_lastPos = currPost;
|
||||
|
||||
switch (segmentModel.skipType) {
|
||||
case SkipType.alwaysSkip:
|
||||
case SkipType.skipOnce:
|
||||
segmentModel.hasSkipped = true;
|
||||
final videoPlayerController =
|
||||
plPlayerController.videoPlayerController!;
|
||||
if (videoPlayerController.state.playing) {
|
||||
future = onSkip(
|
||||
segmentModel,
|
||||
);
|
||||
} else {
|
||||
videoPlayerController.stream.playing.firstWhere((
|
||||
e,
|
||||
) {
|
||||
if (e) {
|
||||
future = onSkip(
|
||||
segmentModel,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
case SkipType.skipManually:
|
||||
onAddItem(segmentModel);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return segmentModel;
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
// _segmentProgressList
|
||||
segmentProgressList.addAll(
|
||||
segmentList.map((e) {
|
||||
double start = (e.segment.first / duration).clamp(0.0, 1.0);
|
||||
double end = (e.segment.second / duration).clamp(0.0, 1.0);
|
||||
return Segment(
|
||||
start: start,
|
||||
end: end,
|
||||
color: _getColor(e.segmentType),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
if (positionSubscription == null &&
|
||||
(autoPlay.value || plPlayerController.preInitPlayer)) {
|
||||
await future;
|
||||
initSkip();
|
||||
}
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('failed to parse sponsorblock: $e');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void initSkip() {
|
||||
if (isClosed) return;
|
||||
if (segmentList.isNotEmpty) {
|
||||
positionSubscription?.cancel();
|
||||
positionSubscription = plPlayerController
|
||||
.videoPlayerController
|
||||
?.stream
|
||||
.position
|
||||
.listen((position) {
|
||||
int currentPos = position.inSeconds;
|
||||
if (currentPos != _lastPos) {
|
||||
_lastPos = currentPos;
|
||||
final msPos = currentPos * 1000;
|
||||
for (SegmentModel item in segmentList) {
|
||||
// if (kDebugMode) {
|
||||
// debugPrint(
|
||||
// '${position.inSeconds},,${item.segment.first},,${item.segment.second},,${item.skipType.name},,${item.hasSkipped}');
|
||||
// }
|
||||
if (msPos <= item.segment.first &&
|
||||
item.segment.first <= msPos + 1000) {
|
||||
switch (item.skipType) {
|
||||
case SkipType.alwaysSkip:
|
||||
onSkip(item, isSeek: false);
|
||||
break;
|
||||
case SkipType.skipOnce:
|
||||
if (!item.hasSkipped) {
|
||||
item.hasSkipped = true;
|
||||
onSkip(item, isSeek: false);
|
||||
}
|
||||
break;
|
||||
case SkipType.skipManually:
|
||||
onAddItem(item);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void onAddItem(dynamic item) {
|
||||
if (listData.contains(item)) return;
|
||||
listData.insert(0, item);
|
||||
listKey.currentState?.insertItem(0);
|
||||
skipTimer ??= Timer.periodic(const Duration(seconds: 4), (_) {
|
||||
if (listData.isNotEmpty) {
|
||||
onRemoveItem(listData.length - 1, listData.last);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void cancelSkipTimer() {
|
||||
skipTimer?.cancel();
|
||||
skipTimer = null;
|
||||
}
|
||||
|
||||
void onRemoveItem(int index, item) {
|
||||
EasyThrottle.throttle(
|
||||
'onRemoveItem',
|
||||
const Duration(milliseconds: 500),
|
||||
() {
|
||||
try {
|
||||
listData.removeAt(index);
|
||||
if (listData.isEmpty) {
|
||||
cancelSkipTimer();
|
||||
}
|
||||
listKey.currentState?.removeItem(
|
||||
index,
|
||||
(context, animation) => buildItem(item, animation),
|
||||
);
|
||||
} catch (_) {}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildItem(dynamic item, Animation<double> animation) {
|
||||
final theme = Get.theme;
|
||||
return Align(
|
||||
@@ -995,36 +563,6 @@ class VideoDetailController extends GetxController
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> onSkip(
|
||||
SegmentModel item, {
|
||||
bool isSkip = true,
|
||||
bool isSeek = true,
|
||||
}) async {
|
||||
try {
|
||||
await plPlayerController.seekTo(
|
||||
Duration(milliseconds: item.segment.second),
|
||||
isSeek: isSeek,
|
||||
);
|
||||
if (isSkip) {
|
||||
if (autoPlay.value && Pref.blockToast) {
|
||||
_showBlockToast('已跳过${item.segmentType.shortTitle}片段');
|
||||
}
|
||||
if (_isBlock && Pref.blockTrack) {
|
||||
SponsorBlock.viewedVideoSponsorTime(item.UUID);
|
||||
}
|
||||
} else {
|
||||
_showBlockToast('已跳至${item.segmentType.shortTitle}');
|
||||
}
|
||||
} catch (e) {
|
||||
if (kDebugMode) debugPrint('failed to skip: $e');
|
||||
if (isSkip) {
|
||||
_showBlockToast('${item.segmentType.shortTitle}片段跳过失败');
|
||||
} else {
|
||||
_showBlockToast('跳转失败');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
({int mode, int fontSize, Color color})? dmConfig;
|
||||
String? savedDanmaku;
|
||||
|
||||
@@ -1035,7 +573,7 @@ class VideoDetailController extends GetxController
|
||||
return;
|
||||
}
|
||||
final isPlaying =
|
||||
autoPlay.value && plPlayerController.playerStatus.isPlaying;
|
||||
_autoPlay.value && plPlayerController.playerStatus.isPlaying;
|
||||
if (isPlaying) {
|
||||
await plPlayerController.pause();
|
||||
}
|
||||
@@ -1095,7 +633,7 @@ class VideoDetailController extends GetxController
|
||||
void updatePlayer() {
|
||||
final currentVideoQa = this.currentVideoQa.value;
|
||||
if (currentVideoQa == null) return;
|
||||
autoPlay.value = true;
|
||||
_autoPlay.value = true;
|
||||
playedTime = plPlayerController.position.value;
|
||||
plPlayerController
|
||||
..removeListeners()
|
||||
@@ -1122,7 +660,7 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
|
||||
Future<void>? _initPlayerIfNeeded() {
|
||||
if (autoPlay.value ||
|
||||
if (_autoPlay.value ||
|
||||
(plPlayerController.preInitPlayer && !plPlayerController.processing) &&
|
||||
(isFileSource
|
||||
? true
|
||||
@@ -1167,7 +705,7 @@ class VideoDetailController extends GetxController
|
||||
aid: aid,
|
||||
bvid: bvid,
|
||||
cid: cid.value,
|
||||
autoplay: autoplay ?? autoPlay.value,
|
||||
autoplay: autoplay ?? _autoPlay.value,
|
||||
epid: isUgc ? null : epId,
|
||||
seasonId: isUgc ? null : seasonId,
|
||||
pgcType: isUgc ? null : pgcType,
|
||||
@@ -1233,8 +771,8 @@ class VideoDetailController extends GetxController
|
||||
return;
|
||||
}
|
||||
isQuerying = true;
|
||||
if (plPlayerController.enableSponsorBlock && _isBlock && !fromReset) {
|
||||
_querySponsorBlock();
|
||||
if (plPlayerController.enableSponsorBlock && isBlock && !fromReset) {
|
||||
querySponsorBlock(bvid: bvid, cid: cid.value);
|
||||
}
|
||||
if (plPlayerController.cacheVideoQa == null) {
|
||||
final isWiFi = await Utils.isWiFi;
|
||||
@@ -1279,8 +817,7 @@ class VideoDetailController extends GetxController
|
||||
|
||||
if (!isUgc && !fromReset && plPlayerController.enablePgcSkip) {
|
||||
if (data.clipInfoList case final clipInfoList?) {
|
||||
positionSubscription?.cancel();
|
||||
positionSubscription = null;
|
||||
resetBlock();
|
||||
handleSBData(clipInfoList);
|
||||
}
|
||||
}
|
||||
@@ -1313,7 +850,7 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
if (data.dash == null) {
|
||||
SmartDialog.showToast('视频资源不存在');
|
||||
autoPlay.value = false;
|
||||
_autoPlay.value = false;
|
||||
videoState.value = const Error('视频资源不存在');
|
||||
if (plPlayerController.isFullScreen.value) {
|
||||
plPlayerController.toggleFullScreen(false);
|
||||
@@ -1408,7 +945,7 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
await _initPlayerIfNeeded();
|
||||
} else {
|
||||
autoPlay.value = false;
|
||||
_autoPlay.value = false;
|
||||
videoState.value = result..toast();
|
||||
if (plPlayerController.isFullScreen.value) {
|
||||
plPlayerController.toggleFullScreen(false);
|
||||
@@ -1417,6 +954,7 @@ class VideoDetailController extends GetxController
|
||||
isQuerying = false;
|
||||
}
|
||||
|
||||
late final List<PostSegmentModel> postList = <PostSegmentModel>[];
|
||||
void onBlock(BuildContext context) {
|
||||
if (postList.isEmpty) {
|
||||
postList.add(
|
||||
@@ -1656,9 +1194,6 @@ class VideoDetailController extends GetxController
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
cancelSkipTimer();
|
||||
positionSubscription?.cancel();
|
||||
positionSubscription = null;
|
||||
cid.close();
|
||||
if (isFileSource) {
|
||||
cacheLocalProgress();
|
||||
@@ -1713,13 +1248,8 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
|
||||
// sponsor block
|
||||
if (plPlayerController.enableBlock) {
|
||||
_lastPos = null;
|
||||
positionSubscription?.cancel();
|
||||
positionSubscription = null;
|
||||
videoLabel.value = '';
|
||||
segmentList.clear();
|
||||
segmentProgressList.clear();
|
||||
if (blockConfig.enableBlock) {
|
||||
resetBlock();
|
||||
}
|
||||
|
||||
// interactive video
|
||||
@@ -1842,7 +1372,7 @@ class VideoDetailController extends GetxController
|
||||
oid: aid,
|
||||
subId: [cid.value],
|
||||
from: from,
|
||||
heroTag: autoPlay.value ? heroTag : null,
|
||||
heroTag: _autoPlay.value ? heroTag : null,
|
||||
start: playedTime,
|
||||
audioUrl: audioUrl,
|
||||
extraId: extraId,
|
||||
|
||||
Reference in New Issue
Block a user