feat: bili comm antifraud

Closes #275

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-17 18:45:08 +08:00
parent 957c326148
commit 7ddc3adfaa
15 changed files with 196 additions and 112 deletions

View File

@@ -1,4 +1,9 @@
import 'dart:convert';
import 'dart:io';
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/reply.dart';
import 'package:PiliPlus/models/common/reply_type.dart';
@@ -8,6 +13,7 @@ import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:android_intent_plus/android_intent.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -33,9 +39,15 @@ abstract class ReplyController extends CommonController {
late bool hasUpTop = false;
late final banWordForReply = GStorage.banWordForReply;
late final enableCommAntifraud = GStorage.enableCommAntifraud;
late final antiGoodsReply = GStorage.antiGoodsReply;
// comment antifraud
late final _enableCommAntifraud = GStorage.enableCommAntifraud;
late final _biliSendCommAntifraud = GStorage.biliSendCommAntifraud;
bool get enableCommAntifraud =>
_enableCommAntifraud || _biliSendCommAntifraud;
dynamic get sourceId;
@override
void onInit() {
super.onInit();
@@ -210,14 +222,22 @@ abstract class ReplyController extends CommonController {
loadingState.value = LoadingState.success(response);
if (enableCommAntifraud && context.mounted) {
checkReply(
context,
oid ?? replyItem.oid.toInt(),
replyItem?.id.toInt(),
replyItem?.type.toInt() ??
context: context,
oid: oid ?? replyItem.oid.toInt(),
rpid: replyItem?.id.toInt(),
replyType: replyItem?.type.toInt() ??
replyType?.index ??
ReplyType.video.index,
replyInfo.id.toInt(),
replyInfo.content.message,
replyId: replyInfo.id.toInt(),
message: replyInfo.content.message,
//
root: replyInfo.root.toInt(),
parent: replyInfo.parent.toInt(),
ctime: replyInfo.ctime.toInt(),
pictures: replyInfo.content.pictures
.map((item) => item.toProto3Json())
.toList(),
mid: replyInfo.mid.toInt(),
);
}
} else {
@@ -236,14 +256,20 @@ abstract class ReplyController extends CommonController {
loadingState.value = LoadingState.success(response);
if (enableCommAntifraud && context.mounted) {
checkReply(
context,
oid ?? replyItem.oid,
replyItem?.rpid,
replyItem?.type.toInt() ??
context: context,
oid: oid ?? replyItem.oid,
rpid: replyItem?.rpid,
replyType: replyItem?.type.toInt() ??
replyType?.index ??
ReplyType.video.index,
replyInfo.rpid ?? 0,
replyInfo.content?.message ?? '',
replyId: replyInfo.rpid ?? 0,
message: replyInfo.content?.message ?? '',
//
root: replyInfo.root,
parent: replyInfo.parent,
ctime: replyInfo.ctime,
pictures: replyInfo.content?.pictures,
mid: replyInfo.mid,
);
}
}
@@ -291,14 +317,56 @@ abstract class ReplyController extends CommonController {
}
// ref https://github.com/freedom-introvert/biliSendCommAntifraud
void checkReply(
BuildContext context,
dynamic oid,
dynamic rpid,
int replyType,
int replyId,
String message,
) async {
void checkReply({
required BuildContext context,
required dynamic oid,
required dynamic rpid,
required int replyType,
required int replyId,
required String message,
dynamic root,
dynamic parent,
dynamic ctime,
dynamic pictures,
dynamic mid,
}) async {
await Future.delayed(const Duration(seconds: 5));
// biliSendCommAntifraud
if (_biliSendCommAntifraud && Platform.isAndroid) {
try {
List<Cookie> cookies = await Request.cookieManager.cookieJar
.loadForRequest(Uri.parse(HttpString.apiBaseUrl));
final List<String> cookieString = cookies
.map((Cookie cookie) => '${cookie.name}=${cookie.value}')
.toList();
AndroidIntent intent = AndroidIntent(
package: 'icu.freedomIntrovert.biliSendCommAntifraud',
componentName:
'icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity',
arguments: {
'action': 0,
'oid': oid,
'type': replyType,
'rpid': replyId,
'root': root,
'parent': parent,
'ctime': ctime,
'comment_text': message,
if (pictures.isNotEmpty == true) 'pictures': jsonEncode(pictures),
'source_id': sourceId,
'uid': mid,
'cookies': cookieString,
},
);
intent.launch();
} catch (e) {
debugPrint('biliSendCommAntifraud: $e');
}
return;
}
// CommAntifraud
void showReplyCheckResult(String message) {
showDialog(
context: context,
@@ -309,7 +377,6 @@ abstract class ReplyController extends CommonController {
);
}
await Future.delayed(const Duration(seconds: 5));
if (context.mounted.not) return;
// root reply
if (rpid == null) {

View File

@@ -1,8 +1,10 @@
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/reply_type.dart';
import 'package:PiliPlus/models/dynamics/result.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:get/get.dart';
import 'package:PiliPlus/http/html.dart';
@@ -11,13 +13,17 @@ import 'package:fixnum/fixnum.dart' as $fixnum;
class DynamicDetailController extends ReplyController {
DynamicDetailController(this.oid, this.type);
int? oid;
int? type;
int oid;
int type;
late DynamicItemModel item;
int? floor;
late final horizontalPreview = GStorage.horizontalPreview;
@override
dynamic get sourceId =>
type == ReplyType.video.index ? IdUtils.av2bv(oid) : oid;
@override
void onInit() {
super.onInit();
@@ -42,8 +48,8 @@ class DynamicDetailController extends ReplyController {
@override
Future<LoadingState> customGetData() => GlobalData().grpcReply
? ReplyHttp.replyListGrpc(
type: type ?? 1,
oid: oid!,
type: type,
oid: oid,
cursor: CursorReq(
next: cursor?.next ?? $fixnum.Int64(0),
mode: mode.value,
@@ -53,9 +59,9 @@ class DynamicDetailController extends ReplyController {
)
: ReplyHttp.replyList(
isLogin: isLogin,
oid: oid!,
oid: oid,
nextOffset: nextOffset,
type: type!,
type: type,
sort: sortType.value.index,
page: currentPage,
banWordForReply: banWordForReply,

View File

@@ -27,7 +27,6 @@ import 'package:PiliPlus/pages/dynamics/detail/index.dart';
import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart';
import 'package:PiliPlus/pages/video/detail/reply_reply/index.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:share_plus/share_plus.dart';
import '../../../utils/grid.dart';
@@ -430,11 +429,9 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
heroTag: null,
onPressed: () {
feedBack();
dynamic oid = _dynamicDetailController.oid ??
IdUtils.bv2av(Get.parameters['bvid']!);
_dynamicDetailController.onReply(
context,
oid: oid,
oid: _dynamicDetailController.oid,
replyType: ReplyType.values[replyType],
);
},

View File

@@ -26,6 +26,9 @@ class HtmlRenderController extends ReplyController {
late final horizontalPreview = GStorage.horizontalPreview;
@override
dynamic get sourceId => id;
@override
void onInit() {
super.onInit();

View File

@@ -42,6 +42,7 @@ import 'package:auto_orientation/auto_orientation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
@@ -1967,6 +1968,14 @@ List<SettingsModel> get extraSettings => [
setKey: SettingBoxKey.enableCommAntifraud,
defaultVal: false,
),
SettingsModel(
settingsType: SettingsType.sw1tch,
title: '使用「哔哩发评反诈」检查评论',
subtitle: '仅对Android生效',
leading: Icon(FontAwesomeIcons.b),
setKey: SettingBoxKey.biliSendCommAntifraud,
defaultVal: false,
),
SettingsModel(
settingsType: SettingsType.sw1tch,
title: '屏蔽带货动态',

View File

@@ -4,25 +4,21 @@ import 'package:PiliPlus/models/common/reply_type.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/http/reply.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:fixnum/fixnum.dart' as $fixnum;
class VideoReplyController extends ReplyController {
VideoReplyController(
this.aid,
this.rpid,
this.replyLevel,
);
VideoReplyController({required this.aid});
// 视频aid 请求时使用的oid
int? aid;
// 层级 2为楼中楼
String? replyLevel;
// rpid 请求楼中楼回复
String? rpid;
int aid;
@override
dynamic get sourceId => IdUtils.av2bv(aid);
@override
Future<LoadingState> customGetData() => GlobalData().grpcReply
? ReplyHttp.replyListGrpc(
oid: aid!,
oid: aid,
cursor: CursorReq(
next: cursor?.next ?? $fixnum.Int64(0),
mode: mode.value,
@@ -32,7 +28,7 @@ class VideoReplyController extends ReplyController {
)
: ReplyHttp.replyList(
isLogin: isLogin,
oid: aid!,
oid: aid,
nextOffset: nextOffset,
type: ReplyType.video.index,
sort: sortType.value.index,

View File

@@ -14,12 +14,11 @@ import 'package:get/get.dart';
import 'package:PiliPlus/common/skeleton/video_reply.dart';
import 'package:PiliPlus/models/common/reply_type.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'controller.dart';
class VideoReplyPanel extends StatefulWidget {
final String? bvid;
final int? oid;
final int oid;
final int rpid;
final String? replyLevel;
final String heroTag;
@@ -31,7 +30,7 @@ class VideoReplyPanel extends StatefulWidget {
const VideoReplyPanel({
super.key,
this.bvid,
this.oid,
required this.oid,
this.rpid = 0,
this.replyLevel,
required this.heroTag,
@@ -65,13 +64,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
// heroTag = Get.arguments['heroTag'];
heroTag = widget.heroTag;
replyLevel = widget.replyLevel ?? '1';
if (replyLevel == '2') {
_videoReplyController = Get.put(
VideoReplyController(widget.oid, widget.rpid.toString(), replyLevel),
tag: widget.rpid.toString());
} else {
_videoReplyController = Get.find<VideoReplyController>(tag: heroTag);
}
_videoReplyController = Get.find<VideoReplyController>(tag: heroTag);
fabAnimationCtr = AnimationController(
vsync: this, duration: const Duration(milliseconds: 100));
@@ -196,11 +189,9 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
heroTag: null,
onPressed: () {
feedBack();
dynamic oid = _videoReplyController.aid ??
IdUtils.bv2av(Get.parameters['bvid']!);
_videoReplyController.onReply(
context,
oid: oid,
oid: _videoReplyController.aid,
replyType: ReplyType.video,
);
},

View File

@@ -3,6 +3,7 @@ import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/video/reply/item.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/utils/global_data.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
@@ -27,9 +28,9 @@ class VideoReplyReplyController extends ReplyController
bool hasRoot = false;
int? id;
// 视频aid 请求时使用的oid
int? oid;
int oid;
// rpid 请求楼中楼回复
int? rpid;
int rpid;
ReplyType replyType; // = ReplyType.video;
int? upMid;
@@ -42,6 +43,10 @@ class VideoReplyReplyController extends ReplyController
late final horizontalPreview = GStorage.horizontalPreview;
@override
dynamic get sourceId =>
replyType == ReplyType.video ? IdUtils.av2bv(oid) : oid;
@override
void onInit() {
super.onInit();
@@ -49,26 +54,6 @@ class VideoReplyReplyController extends ReplyController
queryData();
}
@override
Future queryData([bool isRefresh = true]) async {
// if (GlobalData().grpcReply &&
// !isDialogue &&
// currentPage == 1 &&
// !hasRoot &&
// firstFloor == null &&
// rpid != null) {
// await GrpcRepo.replyInfo(
// rpid: rpid!,
// ).then((res) {
// if (res['status'] && (res['data']?.mid ?? -1) > 0) {
// firstFloor = res['data'];
// hasRoot = true;
// }
// });
// }
return super.queryData(isRefresh);
}
@override
Future onRefresh() {
cursor = null;
@@ -177,8 +162,8 @@ class VideoReplyReplyController extends ReplyController
Future<LoadingState> customGetData() => isDialogue
? ReplyHttp.dialogListGrpc(
type: replyType.index,
oid: oid!,
root: rpid!,
oid: oid,
root: rpid,
rpid: dialog!,
cursor: CursorReq(
next: cursor?.next,
@@ -190,8 +175,8 @@ class VideoReplyReplyController extends ReplyController
: GlobalData().grpcReply
? ReplyHttp.replyReplyListGrpc(
type: replyType.index,
oid: oid!,
root: rpid!,
oid: oid,
root: rpid,
rpid: id ?? 0,
cursor: CursorReq(
next: cursor?.next,
@@ -202,8 +187,8 @@ class VideoReplyReplyController extends ReplyController
)
: ReplyHttp.replyReplyList(
isLogin: isLogin,
oid: oid!,
root: rpid!,
oid: oid,
root: rpid,
pageNum: currentPage,
type: replyType.index,
banWordForReply: banWordForReply,

View File

@@ -22,8 +22,8 @@ class VideoReplyReplyPanel extends StatefulWidget {
const VideoReplyReplyPanel({
super.key,
this.id,
this.oid,
this.rpid,
required this.oid,
required this.rpid,
this.dialog,
this.firstFloor,
this.source,
@@ -34,8 +34,8 @@ class VideoReplyReplyPanel extends StatefulWidget {
this.onDismissed,
});
final int? id;
final int? oid;
final int? rpid;
final int oid;
final int rpid;
final int? dialog;
final dynamic firstFloor;
final String? source;
@@ -366,12 +366,20 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel>
LoadingState.success(list);
if (_videoReplyReplyController.enableCommAntifraud && mounted) {
_videoReplyReplyController.checkReply(
context,
oid,
root,
widget.replyType.index,
replyInfo.id.toInt(),
replyInfo.content.message,
context: context,
oid: oid,
rpid: root,
replyType: widget.replyType.index,
replyId: replyInfo.id.toInt(),
message: replyInfo.content.message,
//
root: replyInfo.root.toInt(),
parent: replyInfo.parent.toInt(),
ctime: replyInfo.ctime.toInt(),
pictures: replyInfo.content.pictures
.map((item) => item.toProto3Json())
.toList(),
mid: replyInfo.mid.toInt(),
);
}
} else {
@@ -386,12 +394,18 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel>
LoadingState.success(list);
if (_videoReplyReplyController.enableCommAntifraud && mounted) {
_videoReplyReplyController.checkReply(
context,
oid,
root,
widget.replyType.index,
replyInfo.rpid ?? 0,
replyInfo.content?.message ?? '',
context: context,
oid: oid,
rpid: root,
replyType: widget.replyType.index,
replyId: replyInfo.rpid ?? 0,
message: replyInfo.content?.message ?? '',
//
root: replyInfo.root,
parent: replyInfo.parent,
ctime: replyInfo.ctime,
pictures: replyInfo.content?.pictures,
mid: replyInfo.mid,
);
}
}

View File

@@ -121,8 +121,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
if (videoDetailController.showReply) {
_videoReplyController = Get.put(
VideoReplyController(videoDetailController.oid.value, '0', '1'),
tag: heroTag);
VideoReplyController(aid: videoDetailController.oid.value),
tag: heroTag,
);
}
videoIntroController = Get.put(VideoIntroController(), tag: heroTag);
_listenerDetail = videoIntroController.videoDetail.listen((value) {

View File

@@ -90,9 +90,8 @@ class PiliScheme {
// to check
// to video reply
String? oid = RegExp(r'/(\d+)').firstMatch(path)?.group(1);
if (oid != null) {
int? rpid =
int.tryParse(uri.queryParameters['comment_root_id']!);
int? rpid = int.tryParse(uri.queryParameters['comment_root_id']!);
if (oid != null && rpid != null) {
Get.to(
() => Scaffold(
resizeToAvoidBottomInset: false,
@@ -233,9 +232,9 @@ class PiliScheme {
if (path.startsWith("/detail/")) {
if (uri.queryParameters['comment_root_id'] != null) {
String? oid = RegExp(r'/(\d+)').firstMatch(path)?.group(1);
if (oid != null) {
int? rpid =
int.tryParse(uri.queryParameters['comment_root_id']!);
int? rpid =
int.tryParse(uri.queryParameters['comment_root_id']!);
if (oid != null && rpid != null) {
Get.to(
() => Scaffold(
resizeToAvoidBottomInset: false,
@@ -252,7 +251,7 @@ class PiliScheme {
],
),
body: VideoReplyReplyPanel(
oid: int.tryParse(oid),
oid: int.parse(oid),
rpid: rpid,
source: 'routePush',
replyType: ReplyType.dynamics,

View File

@@ -366,6 +366,9 @@ class GStorage {
static bool get enableCommAntifraud => GStorage.setting
.get(SettingBoxKey.enableCommAntifraud, defaultValue: false);
static bool get biliSendCommAntifraud => GStorage.setting
.get(SettingBoxKey.biliSendCommAntifraud, defaultValue: false);
static bool get coinWithLike =>
GStorage.setting.get(SettingBoxKey.coinWithLike, defaultValue: false);
@@ -609,6 +612,7 @@ class SettingBoxKey {
showSeekPreview = 'showSeekPreview',
showDmChart = 'showDmChart',
enableCommAntifraud = 'enableCommAntifraud',
biliSendCommAntifraud = 'biliSendCommAntifraud',
coinWithLike = 'coinWithLike',
isPureBlackTheme = 'isPureBlackTheme',
antiGoodsDyn = 'antiGoodsDyn',

View File

@@ -310,8 +310,11 @@ class Utils {
/// 点击评论action 直接查看评论
if (action == 'comment') {
Utils.toDupNamed('/dynamicDetail',
arguments: {'item': item, 'floor': floor, 'action': action});
Utils.toDupNamed('/dynamicDetail', arguments: {
'item': item,
'floor': floor,
'action': action,
});
return;
}