mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-30 23:58:13 +08:00
refa: sb & feat: sb portVideo (WIP) (#1751)
* refa: sb * feat: sb portVideo (WIP) * fix: keep-alive * revert: ua version * fix * tweak [skip ci] Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me> --------- Co-authored-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
committed by
GitHub
parent
d5d95671ff
commit
2be13e7283
@@ -10,6 +10,7 @@ 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';
|
||||
@@ -63,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:dio/dio.dart' show Options;
|
||||
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;
|
||||
@@ -492,25 +492,15 @@ class VideoDetailController extends GetxController
|
||||
plPlayerController.blockColor[segment.index];
|
||||
late RxString videoLabel = ''.obs;
|
||||
|
||||
String get blockServer => plPlayerController.blockServer;
|
||||
|
||||
Timer? skipTimer;
|
||||
late final listKey = GlobalKey<AnimatedListState>();
|
||||
late final List listData = [];
|
||||
|
||||
void _vote(String uuid, int type) {
|
||||
Request()
|
||||
.post(
|
||||
'$blockServer/api/voteOnSponsorTime',
|
||||
queryParameters: {
|
||||
'UUID': uuid,
|
||||
'userID': Pref.blockUserID,
|
||||
'type': type,
|
||||
},
|
||||
)
|
||||
.then((res) {
|
||||
SmartDialog.showToast(res.statusCode == 200 ? '投票成功' : '投票失败');
|
||||
});
|
||||
SponsorBlock.voteOnSponsorTime(
|
||||
uuid: uuid,
|
||||
type: type,
|
||||
).then((i) => SmartDialog.showToast(i.isSuccess ? '投票成功' : '投票失败: $i'));
|
||||
}
|
||||
|
||||
void _showCategoryDialog(BuildContext context, SegmentModel segment) {
|
||||
@@ -528,20 +518,14 @@ class VideoDetailController extends GetxController
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Get.back();
|
||||
Request()
|
||||
.post(
|
||||
'$blockServer/api/voteOnSponsorTime',
|
||||
queryParameters: {
|
||||
'UUID': segment.UUID,
|
||||
'userID': Pref.blockUserID,
|
||||
'category': item.name,
|
||||
},
|
||||
)
|
||||
.then((res) {
|
||||
SmartDialog.showToast(
|
||||
'类别更改${res.statusCode == 200 ? '成功' : '失败'}',
|
||||
);
|
||||
});
|
||||
SponsorBlock.voteOnSponsorTime(
|
||||
uuid: segment.UUID,
|
||||
category: item,
|
||||
).then((i) {
|
||||
SmartDialog.showToast(
|
||||
'类别更改${i.isSuccess ? '成功' : '失败: $i'}',
|
||||
);
|
||||
});
|
||||
},
|
||||
title: Text.rich(
|
||||
TextSpan(
|
||||
@@ -736,18 +720,19 @@ class VideoDetailController extends GetxController
|
||||
videoLabel.value = '';
|
||||
segmentList.clear();
|
||||
segmentProgressList.clear();
|
||||
final result = await Request().get(
|
||||
'$blockServer/api/skipSegments',
|
||||
queryParameters: {
|
||||
'videoID': bvid,
|
||||
'cid': cid.value,
|
||||
},
|
||||
options: Options(validateStatus: (status) => true),
|
||||
|
||||
final result = await SponsorBlock.getSkipSegments(
|
||||
bvid: bvid,
|
||||
cid: cid.value,
|
||||
);
|
||||
if (result.statusCode == 200) {
|
||||
if (result.data case List list) {
|
||||
handleSBData(list.map((e) => SegmentItemModel.fromJson(e)).toList());
|
||||
}
|
||||
switch (result) {
|
||||
case Success<List<SegmentItemModel>>(:final response):
|
||||
handleSBData(response);
|
||||
case Error(:final code) when code != 404:
|
||||
if (kDebugMode) {
|
||||
result.toast();
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,10 +998,7 @@ class VideoDetailController extends GetxController
|
||||
_showBlockToast('已跳过${item.segmentType.shortTitle}片段');
|
||||
}
|
||||
if (_isBlock && Pref.blockTrack) {
|
||||
Request().post(
|
||||
'$blockServer/api/viewedVideoSponsorTime',
|
||||
queryParameters: {'UUID': item.UUID},
|
||||
);
|
||||
SponsorBlock.viewedVideoSponsorTime(item.UUID);
|
||||
}
|
||||
} else {
|
||||
_showBlockToast('已跳至${item.segmentType.shortTitle}');
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/pendant_avatar.dart';
|
||||
import 'package:PiliPlus/common/widgets/scroll_physics.dart';
|
||||
import 'package:PiliPlus/common/widgets/stat/stat.dart';
|
||||
import 'package:PiliPlus/http/sponsor_block.dart';
|
||||
import 'package:PiliPlus/models/common/image_type.dart';
|
||||
import 'package:PiliPlus/models/common/stat_type.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/data.dart';
|
||||
@@ -603,6 +605,11 @@ class _UgcIntroPanelState extends State<UgcIntroPanel> {
|
||||
caseSensitive: false,
|
||||
);
|
||||
|
||||
static final youtubeRegExp = RegExp(
|
||||
r'(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-z0-9_\-]{11})',
|
||||
caseSensitive: false,
|
||||
);
|
||||
|
||||
TextSpan buildContent(ThemeData theme, VideoDetailData content) {
|
||||
if (content.descV2.isNullOrEmpty) {
|
||||
return const TextSpan();
|
||||
@@ -625,12 +632,57 @@ class _UgcIntroPanelState extends State<UgcIntroPanel> {
|
||||
text: matchStr,
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
try {
|
||||
PageUtils.handleWebview(matchStr);
|
||||
} catch (err) {
|
||||
SmartDialog.showToast(err.toString());
|
||||
..onTap = () async {
|
||||
if (videoDetailCtr
|
||||
.plPlayerController
|
||||
.enableSponsorBlock) {
|
||||
final duration =
|
||||
videoDetailCtr.data.timeLength ??
|
||||
videoDetailCtr
|
||||
.plPlayerController
|
||||
.duration
|
||||
.value
|
||||
.inMilliseconds;
|
||||
if (duration > 0) {
|
||||
final ytbId = youtubeRegExp
|
||||
.firstMatch(matchStr)
|
||||
?.group(1);
|
||||
if (ytbId != null) {
|
||||
final bvid = videoDetailCtr.bvid;
|
||||
final cid = videoDetailCtr.cid.value;
|
||||
|
||||
SmartDialog.showLoading();
|
||||
final hasPortVideo =
|
||||
(await SponsorBlock.getPortVideo(
|
||||
bvid: bvid,
|
||||
cid: cid,
|
||||
)).dataOrNull ==
|
||||
ytbId;
|
||||
SmartDialog.dismiss();
|
||||
|
||||
if (!mounted) return;
|
||||
final confirmed = await showConfirmDialog(
|
||||
context: context,
|
||||
title: '空降助手:搬运视频同步',
|
||||
content:
|
||||
'${hasPortVideo ? "" : "是否将"}该视频${hasPortVideo ? "已" : ""}绑定到此YouTube视频($ytbId)',
|
||||
);
|
||||
if (!hasPortVideo && confirmed) {
|
||||
final res = await SponsorBlock.postPortVideo(
|
||||
bvid: bvid,
|
||||
cid: cid,
|
||||
ytbId: ytbId,
|
||||
videoDuration: (duration / 1000).round(),
|
||||
);
|
||||
SmartDialog.showToast(
|
||||
'提交搬运视频${res.isSuccess ? "成功" : "失败: $res"}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PageUtils.handleWebview(matchStr);
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||
import 'package:PiliPlus/common/widgets/pair.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/sponsor_block.dart';
|
||||
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_type.dart';
|
||||
import 'package:PiliPlus/models_new/sponsor_block/segment_item.dart';
|
||||
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/post_panel/popup_menu_text.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||
import 'package:PiliPlus/utils/duration_utils.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:PiliPlus/utils/storage_pref.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
|
||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -310,69 +307,26 @@ class _PostPanelState extends State<PostPanel>
|
||||
|
||||
Future<void> _onPost() async {
|
||||
Get.back();
|
||||
final res = await Request().post(
|
||||
'${widget.videoDetailController.blockServer}/api/skipSegments',
|
||||
data: {
|
||||
'videoID': videoDetailController.bvid,
|
||||
'cid': videoDetailController.cid.value.toString(),
|
||||
'userID': Pref.blockUserID.toString(),
|
||||
'userAgent': Constants.userAgent,
|
||||
'videoDuration': videoDuration,
|
||||
'segments': list
|
||||
.map(
|
||||
(item) => {
|
||||
'segment': [
|
||||
item.segment.first,
|
||||
item.segment.second,
|
||||
],
|
||||
'category': item.category.name,
|
||||
'actionType': item.actionType.name,
|
||||
},
|
||||
)
|
||||
.toList(),
|
||||
},
|
||||
options: Options(
|
||||
followRedirects: true, // Defaults to true.
|
||||
validateStatus: (int? status) {
|
||||
return (status! >= 200 && status < 300) ||
|
||||
const [400, 403, 429, 409] // reduce extra toast
|
||||
.contains(status);
|
||||
},
|
||||
),
|
||||
final res = await SponsorBlock.postSkipSegments(
|
||||
bvid: videoDetailController.bvid,
|
||||
cid: videoDetailController.cid.value,
|
||||
videoDuration: videoDuration,
|
||||
segments: list,
|
||||
);
|
||||
|
||||
if (res.statusCode == 200) {
|
||||
if (res case Success(:final response)) {
|
||||
Get.back();
|
||||
SmartDialog.showToast('提交成功');
|
||||
list.clear();
|
||||
if (res.data case List list) {
|
||||
videoDetailController.handleSBData(
|
||||
list.map((e) => SegmentItemModel.fromJson(e)).toList(),
|
||||
);
|
||||
}
|
||||
videoDetailController.handleSBData(response);
|
||||
if (videoDetailController.positionSubscription == null) {
|
||||
videoDetailController.initSkip();
|
||||
}
|
||||
} else {
|
||||
SmartDialog.showToast('提交失败: ${_errMsg(res)}');
|
||||
SmartDialog.showToast('提交失败: $res');
|
||||
}
|
||||
}
|
||||
|
||||
String _errMsg(Response res) {
|
||||
if (res.data case String e) {
|
||||
if (e.isNotEmpty) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return switch (res.statusCode) {
|
||||
400 => '参数错误',
|
||||
403 => '被自动审核机制拒绝',
|
||||
429 => '重复提交太快',
|
||||
409 => '重复提交',
|
||||
_ => '${res.data}(${res.statusCode})',
|
||||
};
|
||||
}
|
||||
|
||||
Widget _buildItem(ThemeData theme, int index, PostSegmentModel item) {
|
||||
return Stack(
|
||||
clipBehavior: Clip.none,
|
||||
|
||||
Reference in New Issue
Block a user