opt: query sponsor block

Closes #633

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-07 21:52:39 +08:00
parent 4de180c23a
commit 6f2d697748

View File

@@ -41,6 +41,7 @@ import 'package:PiliPlus/utils/utils.dart';
import 'package:PiliPlus/utils/video_utils.dart';
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
import 'package:hive/hive.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:media_kit/media_kit.dart';
import '../../../utils/id_utils.dart';
@@ -633,34 +634,29 @@ class VideoDetailController extends GetxController
item.skipType.title,
style: TextStyle(fontSize: 13),
),
if (item.skipType == SkipType.showOnly &&
item.segment.second != 0)
if (item.segment.second != 0)
SizedBox(
width: 36,
height: 36,
child: IconButton(
tooltip: '跳转至此片段',
tooltip: item.skipType == SkipType.showOnly
? '跳至此片段'
: '跳过此片段',
onPressed: () async {
Get.back();
try {
plPlayerController.danmakuController?.clear();
await plPlayerController.videoPlayerController
?.seek(Duration(
seconds: item.segment.first));
if (GStorage.blockToast) {
_showBlockToast(
'已跳至${item.segmentType.shortTitle}');
}
} catch (e) {
_showBlockToast('跳转失败: $e');
}
onSkip(
item,
item.skipType != SkipType.showOnly,
);
},
style: IconButton.styleFrom(
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
icon: Icon(
Icons.my_location,
item.skipType == SkipType.showOnly
? Icons.my_location
: MdiIcons.debugStepOver,
size: 18,
color: Theme.of(context)
.colorScheme
@@ -695,14 +691,16 @@ class VideoDetailController extends GetxController
videoLabel.value = '';
segmentList.clear();
segmentProgressList = null;
dynamic result = await Request().get(
final result = await Request().get(
'${GStorage.blockServer}/api/skipSegments',
queryParameters: {
'videoID': bvid,
'cid': cid.value,
},
);
handleSBData(result);
if (result.statusCode == 200) {
handleSBData(result);
}
}
void handleSBData(result) {
@@ -736,6 +734,7 @@ class VideoDetailController extends GetxController
skipType = SkipType.showOnly;
}
}
int convert(value) {
return switch (value) {
int() => value,
@@ -744,7 +743,7 @@ class VideoDetailController extends GetxController
};
}
return SegmentModel(
final segmentModel = SegmentModel(
UUID: item['UUID'],
segmentType: segmentType,
segment: Pair(
@@ -753,18 +752,51 @@ class VideoDetailController extends GetxController
),
skipType: skipType,
);
if (item['segment'][0] == 0 &&
item['segment'][1] > 0 &&
!isShowCover.value) {
if (plPlayerController.videoPlayerController != null &&
plPlayerController
.videoPlayerController!.state.position.inSeconds <
item['segment'][1]) {
if (segmentModel.skipType == SkipType.alwaysSkip) {
_lastPos = 0;
plPlayerController.videoPlayerController!.stream.buffer.first
.then((_) {
onSkip(segmentModel);
});
} else if (segmentModel.skipType == SkipType.skipOnce) {
_lastPos = 0;
segmentModel.hasSkipped = true;
plPlayerController.videoPlayerController!.stream.buffer.first
.then((_) {
onSkip(segmentModel);
});
} else if (segmentModel.skipType == SkipType.skipManually) {
onAddItem(segmentModel);
}
}
}
return segmentModel;
},
).toList());
// _segmentProgressList
segmentProgressList ??= <Segment>[];
segmentProgressList!.addAll(segmentList.map((item) {
double start = (item.segment.first / ((data.timeLength ?? 0) / 1000))
.clamp(0.0, 1.0);
double end = (item.segment.second / ((data.timeLength ?? 0) / 1000))
.clamp(0.0, 1.0);
double start =
(item.segment.first / (data.timeLength! / 1000)).clamp(0.0, 1.0);
double end =
(item.segment.second / (data.timeLength! / 1000)).clamp(0.0, 1.0);
return Segment(start, end, _getColor(item.segmentType));
}).toList());
if (positionSubscription == null && autoPlay.value) {
initSkip();
plPlayerController.segmentList.value = segmentProgressList!;
}
} catch (e) {
debugPrint('failed to parse sponsorblock: $e');
}
@@ -773,9 +805,10 @@ class VideoDetailController extends GetxController
void initSkip() {
if (segmentList.isNotEmpty) {
positionSubscription?.cancel();
positionSubscription = plPlayerController
.videoPlayerController?.stream.position
.listen((position) async {
.listen((position) {
if (isShowCover.value) {
return;
}
@@ -804,6 +837,7 @@ class VideoDetailController extends GetxController
}
void onAddItem(item) {
if (listData.contains(item)) return;
listData.insert(0, item);
listKey.currentState?.insertItem(0);
skipTimer ??= Timer.periodic(const Duration(seconds: 4), (_) {
@@ -890,23 +924,31 @@ class VideoDetailController extends GetxController
);
}
void onSkip(SegmentModel item) async {
void onSkip(SegmentModel item, [bool isSkip = true]) async {
try {
plPlayerController.danmakuController?.clear();
await plPlayerController.videoPlayerController
?.seek(Duration(seconds: item.segment.second));
if (GStorage.blockToast) {
_showBlockToast('已跳过${item.segmentType.shortTitle}片段');
}
if (GStorage.blockTrack) {
Request().post(
'${GStorage.blockServer}/api/viewedVideoSponsorTime',
queryParameters: {'UUID': item.UUID},
);
if (isSkip) {
if (GStorage.blockToast) {
_showBlockToast('已跳过${item.segmentType.shortTitle}片段');
}
if (GStorage.blockTrack) {
Request().post(
'${GStorage.blockServer}/api/viewedVideoSponsorTime',
queryParameters: {'UUID': item.UUID},
);
}
} else {
_showBlockToast('已跳至${item.segmentType.shortTitle}');
}
} catch (e) {
debugPrint('failed to skip: $e');
_showBlockToast('${item.segmentType.shortTitle}片段跳过失败');
if (isSkip) {
_showBlockToast('${item.segmentType.shortTitle}片段跳过失败');
} else {
_showBlockToast('跳转失败');
}
}
}
@@ -1134,7 +1176,7 @@ class VideoDetailController extends GetxController
data = result['data'];
if (enableSponsorBlock) {
await _querySponsorBlock();
_querySponsorBlock();
}
if (data.acceptDesc!.isNotEmpty && data.acceptDesc!.contains('试看')) {
@@ -1457,23 +1499,25 @@ class VideoDetailController extends GetxController
if (GStorage.showViewPoints &&
res["view_points"] is List &&
res["view_points"].isNotEmpty) {
viewPointList = (res["view_points"] as List).map((item) {
double start =
(item['to'] / ((data.timeLength ?? 0) / 1000)).clamp(0.0, 1.0);
return Segment(
start,
start,
Colors.black.withOpacity(0.5),
item?['content'],
item?['imgUrl'],
item?['from'],
item?['to'],
);
}).toList();
if (plPlayerController.viewPointList.isEmpty) {
plPlayerController.viewPointList.value = viewPointList;
plPlayerController.showVP.value = showVP = true;
}
try {
viewPointList = (res["view_points"] as List).map((item) {
double start =
(item['to'] / (data.timeLength! / 1000)).clamp(0.0, 1.0);
return Segment(
start,
start,
Colors.black.withOpacity(0.5),
item?['content'],
item?['imgUrl'],
item?['from'],
item?['to'],
);
}).toList();
if (plPlayerController.viewPointList.isEmpty) {
plPlayerController.viewPointList.value = viewPointList;
plPlayerController.showVP.value = showVP = true;
}
} catch (_) {}
}
if (res["subtitles"] is List && res["subtitles"].isNotEmpty) {
@@ -1563,6 +1607,7 @@ class VideoDetailController extends GetxController
// sponsor block
if (enableSponsorBlock) {
positionSubscription?.cancel();
positionSubscription = null;
videoLabel.value = '';
segmentList.clear();
segmentProgressList = null;