mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: anti goods reply
Closes #276 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -29,6 +29,8 @@ class Constants {
|
||||
static const urlPattern =
|
||||
r'https?://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]';
|
||||
|
||||
static const goodsUrlPrefix = "https://gaoneng.bilibili.com/tetris";
|
||||
|
||||
// 超分辨率滤镜
|
||||
static const List<String> mpvAnime4KShaders = [
|
||||
'Anime4K_Clamp_Highlights.glsl',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart';
|
||||
import 'package:PiliPlus/grpc/grpc_repo.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models/video/reply/item.dart';
|
||||
import 'package:PiliPlus/utils/extension.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
@@ -20,6 +22,7 @@ class ReplyHttp {
|
||||
required int page,
|
||||
int sort = 1,
|
||||
required String banWordForReply,
|
||||
required bool antiGoodsReply,
|
||||
}) async {
|
||||
var res = !isLogin
|
||||
? await Request().get(
|
||||
@@ -81,6 +84,37 @@ class ReplyHttp {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// antiGoodsReply
|
||||
if (antiGoodsReply) {
|
||||
// topReplies
|
||||
if (replyData.topReplies?.isNotEmpty == true) {
|
||||
replyData.topReplies!.removeWhere((item) {
|
||||
bool hasMatch = needRemove(item);
|
||||
// remove subreplies
|
||||
if (hasMatch.not) {
|
||||
if (item.replies?.isNotEmpty == true) {
|
||||
item.replies!.removeWhere(needRemove);
|
||||
}
|
||||
}
|
||||
return hasMatch;
|
||||
});
|
||||
}
|
||||
|
||||
// replies
|
||||
if (replyData.replies?.isNotEmpty == true) {
|
||||
replyData.replies!.removeWhere((item) {
|
||||
bool hasMatch = needRemove(item);
|
||||
// remove subreplies
|
||||
if (hasMatch.not) {
|
||||
if (item.replies?.isNotEmpty == true) {
|
||||
item.replies!.removeWhere(needRemove);
|
||||
}
|
||||
}
|
||||
return hasMatch;
|
||||
});
|
||||
}
|
||||
}
|
||||
return LoadingState.success(replyData);
|
||||
} else {
|
||||
return LoadingState.error(res.data['message']);
|
||||
@@ -92,10 +126,12 @@ class ReplyHttp {
|
||||
required int oid,
|
||||
required CursorReq cursor,
|
||||
required String banWordForReply,
|
||||
required bool antiGoodsReply,
|
||||
}) async {
|
||||
dynamic res = await GrpcRepo.mainList(type: type, oid: oid, cursor: cursor);
|
||||
if (res['status']) {
|
||||
MainListReply mainListReply = res['data'];
|
||||
// keyword filter
|
||||
if (banWordForReply.isNotEmpty) {
|
||||
// upTop
|
||||
if (mainListReply.hasUpTop() &&
|
||||
@@ -121,12 +157,65 @@ class ReplyHttp {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// antiGoodsReply
|
||||
if (antiGoodsReply) {
|
||||
// upTop
|
||||
if (mainListReply.hasUpTop() && needRemoveGrpc(mainListReply.upTop)) {
|
||||
mainListReply.clearUpTop();
|
||||
}
|
||||
|
||||
// replies
|
||||
if (mainListReply.replies.isNotEmpty) {
|
||||
mainListReply.replies.removeWhere((item) {
|
||||
bool hasMatch = needRemoveGrpc(item);
|
||||
// remove subreplies
|
||||
if (hasMatch.not) {
|
||||
if (item.replies.isNotEmpty) {
|
||||
item.replies.removeWhere(needRemoveGrpc);
|
||||
}
|
||||
}
|
||||
return hasMatch;
|
||||
});
|
||||
}
|
||||
}
|
||||
return LoadingState.success(mainListReply);
|
||||
} else {
|
||||
return LoadingState.error(res['msg']);
|
||||
}
|
||||
}
|
||||
|
||||
// ref BiliRoamingX
|
||||
static bool needRemoveGrpc(ReplyInfo reply) {
|
||||
if ((reply.content.url.isNotEmpty &&
|
||||
reply.content.url.values.any((url) {
|
||||
return url.hasExtra() &&
|
||||
(url.extra.goodsCmControl == 1 ||
|
||||
url.extra.goodsItemId != 0 ||
|
||||
url.extra.goodsPrefetchedCache.isNotEmpty);
|
||||
})) ||
|
||||
reply.content.message.contains(Constants.goodsUrlPrefix)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool needRemove(ReplyItemModel reply) {
|
||||
try {
|
||||
if ((reply.content?.jumpUrl?.isNotEmpty == true &&
|
||||
reply.content!.jumpUrl!.values.any((url) {
|
||||
return url['extra'] != null &&
|
||||
(url['extra']['goods_cm_control'] == 1 ||
|
||||
url['extra']['goods_item_id'] != 0 ||
|
||||
url['extra']['goods_prefetched_cache'].isNotEmpty);
|
||||
})) ||
|
||||
reply.content?.message?.contains(Constants.goodsUrlPrefix) == true) {
|
||||
return true;
|
||||
}
|
||||
} catch (_) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Future<LoadingState> replyReplyList({
|
||||
required bool isLogin,
|
||||
required int oid,
|
||||
@@ -134,6 +223,7 @@ class ReplyHttp {
|
||||
required int pageNum,
|
||||
required int type,
|
||||
required String banWordForReply,
|
||||
required bool antiGoodsReply,
|
||||
bool? isCheck,
|
||||
}) async {
|
||||
var res = await Request().get(
|
||||
@@ -157,6 +247,11 @@ class ReplyHttp {
|
||||
.hasMatch(item.content?.message ?? ''));
|
||||
}
|
||||
}
|
||||
if (antiGoodsReply) {
|
||||
if (replyData.replies?.isNotEmpty == true) {
|
||||
replyData.replies!.removeWhere(needRemove);
|
||||
}
|
||||
}
|
||||
return LoadingState.success(replyData);
|
||||
} else {
|
||||
return LoadingState.error(
|
||||
@@ -174,6 +269,7 @@ class ReplyHttp {
|
||||
required int rpid,
|
||||
required CursorReq cursor,
|
||||
required String banWordForReply,
|
||||
required bool antiGoodsReply,
|
||||
}) async {
|
||||
dynamic res = await GrpcRepo.detailList(
|
||||
type: type,
|
||||
@@ -191,6 +287,11 @@ class ReplyHttp {
|
||||
.hasMatch(item.content.message));
|
||||
}
|
||||
}
|
||||
if (antiGoodsReply) {
|
||||
if (detailListReply.root.replies.isNotEmpty) {
|
||||
detailListReply.root.replies.removeWhere(needRemoveGrpc);
|
||||
}
|
||||
}
|
||||
return LoadingState.success(detailListReply);
|
||||
} else {
|
||||
return LoadingState.error(res['msg']);
|
||||
@@ -204,6 +305,7 @@ class ReplyHttp {
|
||||
required int rpid,
|
||||
required CursorReq cursor,
|
||||
required String banWordForReply,
|
||||
required bool antiGoodsReply,
|
||||
}) async {
|
||||
dynamic res = await GrpcRepo.dialogList(
|
||||
type: type,
|
||||
@@ -221,6 +323,11 @@ class ReplyHttp {
|
||||
.hasMatch(item.content.message));
|
||||
}
|
||||
}
|
||||
if (antiGoodsReply) {
|
||||
if (dialogListReply.replies.isNotEmpty) {
|
||||
dialogListReply.replies.removeWhere(needRemoveGrpc);
|
||||
}
|
||||
}
|
||||
return LoadingState.success(dialogListReply);
|
||||
} else {
|
||||
return LoadingState.error(res['msg']);
|
||||
|
||||
@@ -34,6 +34,7 @@ abstract class ReplyController extends CommonController {
|
||||
|
||||
late final banWordForReply = GStorage.banWordForReply;
|
||||
late final enableCommAntifraud = GStorage.enableCommAntifraud;
|
||||
late final antiGoodsReply = GStorage.antiGoodsReply;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
@@ -321,6 +322,7 @@ abstract class ReplyController extends CommonController {
|
||||
sort: ReplySortType.time.index,
|
||||
page: 1,
|
||||
banWordForReply: '',
|
||||
antiGoodsReply: false,
|
||||
);
|
||||
if (context.mounted.not) return;
|
||||
if (res is Error) {
|
||||
@@ -348,6 +350,7 @@ abstract class ReplyController extends CommonController {
|
||||
pageNum: 1,
|
||||
type: replyType,
|
||||
banWordForReply: '',
|
||||
antiGoodsReply: false,
|
||||
);
|
||||
if (context.mounted.not) return;
|
||||
if (res1 is Error) {
|
||||
@@ -369,6 +372,7 @@ abstract class ReplyController extends CommonController {
|
||||
type: replyType,
|
||||
banWordForReply: '',
|
||||
isCheck: true,
|
||||
antiGoodsReply: false,
|
||||
);
|
||||
if (context.mounted.not) return;
|
||||
if (res2 is Error) {
|
||||
@@ -405,6 +409,7 @@ https://api.bilibili.com/x/v2/reply/reply?oid=$oid&pn=1&ps=20&root=${rpid ?? rep
|
||||
type: replyType,
|
||||
banWordForReply: '',
|
||||
isCheck: true,
|
||||
antiGoodsReply: false,
|
||||
);
|
||||
if (res3 is Error) {
|
||||
break;
|
||||
@@ -439,6 +444,7 @@ https://api.bilibili.com/x/v2/reply/reply?oid=$oid&pn=1&ps=20&root=${rpid ?? rep
|
||||
type: replyType,
|
||||
banWordForReply: '',
|
||||
isCheck: true,
|
||||
antiGoodsReply: false,
|
||||
);
|
||||
if (res4 is Error) {
|
||||
break;
|
||||
|
||||
@@ -49,6 +49,7 @@ class DynamicDetailController extends ReplyController {
|
||||
mode: mode.value,
|
||||
),
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
)
|
||||
: ReplyHttp.replyList(
|
||||
isLogin: isLogin,
|
||||
@@ -58,5 +59,6 @@ class DynamicDetailController extends ReplyController {
|
||||
sort: sortType.value.index,
|
||||
page: currentPage,
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,7 @@ class HtmlRenderController extends ReplyController {
|
||||
mode: mode.value,
|
||||
),
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
)
|
||||
: ReplyHttp.replyList(
|
||||
isLogin: isLogin,
|
||||
@@ -92,5 +93,6 @@ class HtmlRenderController extends ReplyController {
|
||||
sort: sortType.value.index,
|
||||
page: currentPage,
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1980,6 +1980,19 @@ List<SettingsModel> get extraSettings => [
|
||||
setKey: SettingBoxKey.antiGoodsDyn,
|
||||
defaultVal: false,
|
||||
),
|
||||
SettingsModel(
|
||||
settingsType: SettingsType.sw1tch,
|
||||
title: '屏蔽带货评论',
|
||||
leading: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Icon(Icons.shopping_bag_outlined, size: 14),
|
||||
Icon(Icons.not_interested),
|
||||
],
|
||||
),
|
||||
setKey: SettingBoxKey.antiGoodsReply,
|
||||
defaultVal: false,
|
||||
),
|
||||
SettingsModel(
|
||||
settingsType: SettingsType.sw1tch,
|
||||
enableFeedback: true,
|
||||
|
||||
@@ -28,6 +28,7 @@ class VideoReplyController extends ReplyController {
|
||||
mode: mode.value,
|
||||
),
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
)
|
||||
: ReplyHttp.replyList(
|
||||
isLogin: isLogin,
|
||||
@@ -37,5 +38,6 @@ class VideoReplyController extends ReplyController {
|
||||
sort: sortType.value.index,
|
||||
page: currentPage,
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -185,6 +185,7 @@ class VideoReplyReplyController extends ReplyController
|
||||
mode: mode.value,
|
||||
),
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
)
|
||||
: GlobalData().grpcReply
|
||||
? ReplyHttp.replyReplyListGrpc(
|
||||
@@ -197,6 +198,7 @@ class VideoReplyReplyController extends ReplyController
|
||||
mode: mode.value,
|
||||
),
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
)
|
||||
: ReplyHttp.replyReplyList(
|
||||
isLogin: isLogin,
|
||||
@@ -205,6 +207,7 @@ class VideoReplyReplyController extends ReplyController
|
||||
pageNum: currentPage,
|
||||
type: replyType.index,
|
||||
banWordForReply: banWordForReply,
|
||||
antiGoodsReply: antiGoodsReply,
|
||||
);
|
||||
|
||||
@override
|
||||
|
||||
@@ -375,6 +375,9 @@ class GStorage {
|
||||
static bool get antiGoodsDyn =>
|
||||
GStorage.setting.get(SettingBoxKey.antiGoodsDyn, defaultValue: false);
|
||||
|
||||
static bool get antiGoodsReply =>
|
||||
GStorage.setting.get(SettingBoxKey.antiGoodsReply, defaultValue: false);
|
||||
|
||||
static List<double> get dynamicDetailRatio => List<double>.from(setting
|
||||
.get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0]));
|
||||
|
||||
@@ -609,6 +612,7 @@ class SettingBoxKey {
|
||||
coinWithLike = 'coinWithLike',
|
||||
isPureBlackTheme = 'isPureBlackTheme',
|
||||
antiGoodsDyn = 'antiGoodsDyn',
|
||||
antiGoodsReply = 'antiGoodsReply',
|
||||
|
||||
// Sponsor Block
|
||||
enableSponsorBlock = 'enableSponsorBlock',
|
||||
|
||||
Reference in New Issue
Block a user