opt: filter data

Closes #283

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-19 15:19:50 +08:00
parent cfb6c674ea
commit f22cad42d7
9 changed files with 53 additions and 65 deletions

View File

@@ -4,6 +4,7 @@ import 'package:PiliPlus/grpc/grpc_repo.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/video/reply/item.dart'; import 'package:PiliPlus/models/video/reply/item.dart';
import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import '../models/video/reply/data.dart'; import '../models/video/reply/data.dart';
@@ -14,6 +15,9 @@ import 'init.dart';
class ReplyHttp { class ReplyHttp {
static Options get _options => Options(extra: {'clearCookie': true}); static Options get _options => Options(extra: {'clearCookie': true});
static RegExp replyRegExp =
RegExp(GStorage.banWordForReply, caseSensitive: false);
static Future<LoadingState> replyList({ static Future<LoadingState> replyList({
required bool isLogin, required bool isLogin,
required int oid, required int oid,
@@ -21,8 +25,8 @@ class ReplyHttp {
required int type, required int type,
required int page, required int page,
int sort = 1, int sort = 1,
required String banWordForReply,
required bool antiGoodsReply, required bool antiGoodsReply,
bool? enableFilter,
}) async { }) async {
var res = !isLogin var res = !isLogin
? await Request().get( ? await Request().get(
@@ -49,18 +53,16 @@ class ReplyHttp {
); );
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
ReplyData replyData = ReplyData.fromJson(res.data['data']); ReplyData replyData = ReplyData.fromJson(res.data['data']);
if (banWordForReply.isNotEmpty) { if (enableFilter != false && replyRegExp.pattern.isNotEmpty) {
// topReplies // topReplies
if (replyData.topReplies?.isNotEmpty == true) { if (replyData.topReplies?.isNotEmpty == true) {
replyData.topReplies!.removeWhere((item) { replyData.topReplies!.removeWhere((item) {
bool hasMatch = RegExp(banWordForReply, caseSensitive: false) bool hasMatch = replyRegExp.hasMatch(item.content?.message ?? '');
.hasMatch(item.content?.message ?? '');
// remove subreplies // remove subreplies
if (hasMatch.not) { if (hasMatch.not) {
if (item.replies?.isNotEmpty == true) { if (item.replies?.isNotEmpty == true) {
item.replies!.removeWhere((item) => item.replies!.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false) replyRegExp.hasMatch(item.content?.message ?? ''));
.hasMatch(item.content?.message ?? ''));
} }
} }
return hasMatch; return hasMatch;
@@ -70,14 +72,12 @@ class ReplyHttp {
// replies // replies
if (replyData.replies?.isNotEmpty == true) { if (replyData.replies?.isNotEmpty == true) {
replyData.replies!.removeWhere((item) { replyData.replies!.removeWhere((item) {
bool hasMatch = RegExp(banWordForReply, caseSensitive: false) bool hasMatch = replyRegExp.hasMatch(item.content?.message ?? '');
.hasMatch(item.content?.message ?? '');
// remove subreplies // remove subreplies
if (hasMatch.not) { if (hasMatch.not) {
if (item.replies?.isNotEmpty == true) { if (item.replies?.isNotEmpty == true) {
item.replies!.removeWhere((item) => item.replies!.removeWhere((item) =>
RegExp(banWordForReply, caseSensitive: false) replyRegExp.hasMatch(item.content?.message ?? ''));
.hasMatch(item.content?.message ?? ''));
} }
} }
return hasMatch; return hasMatch;
@@ -125,32 +125,28 @@ class ReplyHttp {
int type = 1, int type = 1,
required int oid, required int oid,
required CursorReq cursor, required CursorReq cursor,
required String banWordForReply,
required bool antiGoodsReply, required bool antiGoodsReply,
}) async { }) async {
dynamic res = await GrpcRepo.mainList(type: type, oid: oid, cursor: cursor); dynamic res = await GrpcRepo.mainList(type: type, oid: oid, cursor: cursor);
if (res['status']) { if (res['status']) {
MainListReply mainListReply = res['data']; MainListReply mainListReply = res['data'];
// keyword filter // keyword filter
if (banWordForReply.isNotEmpty) { if (replyRegExp.pattern.isNotEmpty) {
// upTop // upTop
if (mainListReply.hasUpTop() && if (mainListReply.hasUpTop() &&
RegExp(banWordForReply, caseSensitive: false) replyRegExp.hasMatch(mainListReply.upTop.content.message)) {
.hasMatch(mainListReply.upTop.content.message)) {
mainListReply.clearUpTop(); mainListReply.clearUpTop();
} }
// replies // replies
if (mainListReply.replies.isNotEmpty) { if (mainListReply.replies.isNotEmpty) {
mainListReply.replies.removeWhere((item) { mainListReply.replies.removeWhere((item) {
bool hasMatch = RegExp(banWordForReply, caseSensitive: false) bool hasMatch = replyRegExp.hasMatch(item.content.message);
.hasMatch(item.content.message);
// remove subreplies // remove subreplies
if (hasMatch.not) { if (hasMatch.not) {
if (item.replies.isNotEmpty) { if (item.replies.isNotEmpty) {
item.replies.removeWhere((item) => item.replies.removeWhere(
RegExp(banWordForReply, caseSensitive: false) (item) => replyRegExp.hasMatch(item.content.message));
.hasMatch(item.content.message));
} }
} }
return hasMatch; return hasMatch;
@@ -222,9 +218,9 @@ class ReplyHttp {
required int root, required int root,
required int pageNum, required int pageNum,
required int type, required int type,
required String banWordForReply,
required bool antiGoodsReply, required bool antiGoodsReply,
bool? isCheck, bool? isCheck,
bool? filterBanWord,
}) async { }) async {
var res = await Request().get( var res = await Request().get(
Api.replyReplyList, Api.replyReplyList,
@@ -240,11 +236,10 @@ class ReplyHttp {
); );
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
ReplyReplyData replyData = ReplyReplyData.fromJson(res.data['data']); ReplyReplyData replyData = ReplyReplyData.fromJson(res.data['data']);
if (banWordForReply.isNotEmpty) { if (filterBanWord != false && replyRegExp.pattern.isNotEmpty) {
if (replyData.replies?.isNotEmpty == true) { if (replyData.replies?.isNotEmpty == true) {
replyData.replies!.removeWhere((item) => replyData.replies!.removeWhere(
RegExp(banWordForReply, caseSensitive: false) (item) => replyRegExp.hasMatch(item.content?.message ?? ''));
.hasMatch(item.content?.message ?? ''));
} }
} }
if (antiGoodsReply) { if (antiGoodsReply) {
@@ -268,7 +263,6 @@ class ReplyHttp {
required int root, required int root,
required int rpid, required int rpid,
required CursorReq cursor, required CursorReq cursor,
required String banWordForReply,
required bool antiGoodsReply, required bool antiGoodsReply,
}) async { }) async {
dynamic res = await GrpcRepo.detailList( dynamic res = await GrpcRepo.detailList(
@@ -280,11 +274,10 @@ class ReplyHttp {
); );
if (res['status']) { if (res['status']) {
DetailListReply detailListReply = res['data']; DetailListReply detailListReply = res['data'];
if (banWordForReply.isNotEmpty) { if (replyRegExp.pattern.isNotEmpty) {
if (detailListReply.root.replies.isNotEmpty) { if (detailListReply.root.replies.isNotEmpty) {
detailListReply.root.replies.removeWhere((item) => detailListReply.root.replies.removeWhere(
RegExp(banWordForReply, caseSensitive: false) (item) => replyRegExp.hasMatch(item.content.message));
.hasMatch(item.content.message));
} }
} }
if (antiGoodsReply) { if (antiGoodsReply) {
@@ -304,7 +297,6 @@ class ReplyHttp {
required int root, required int root,
required int rpid, required int rpid,
required CursorReq cursor, required CursorReq cursor,
required String banWordForReply,
required bool antiGoodsReply, required bool antiGoodsReply,
}) async { }) async {
dynamic res = await GrpcRepo.dialogList( dynamic res = await GrpcRepo.dialogList(
@@ -316,11 +308,10 @@ class ReplyHttp {
); );
if (res['status']) { if (res['status']) {
DialogListReply dialogListReply = res['data']; DialogListReply dialogListReply = res['data'];
if (banWordForReply.isNotEmpty) { if (replyRegExp.pattern.isNotEmpty) {
if (dialogListReply.replies.isNotEmpty) { if (dialogListReply.replies.isNotEmpty) {
dialogListReply.replies.removeWhere((item) => dialogListReply.replies.removeWhere(
RegExp(banWordForReply, caseSensitive: false) (item) => replyRegExp.hasMatch(item.content.message));
.hasMatch(item.content.message));
} }
} }
if (antiGoodsReply) { if (antiGoodsReply) {

View File

@@ -32,6 +32,8 @@ import 'login.dart';
class VideoHttp { class VideoHttp {
static bool enableRcmdDynamic = static bool enableRcmdDynamic =
GStorage.setting.get(SettingBoxKey.enableRcmdDynamic, defaultValue: true); GStorage.setting.get(SettingBoxKey.enableRcmdDynamic, defaultValue: true);
static RegExp zoneRegExp =
RegExp(GStorage.banWordForZone, caseSensitive: false);
// 首页推荐视频 // 首页推荐视频
static Future<LoadingState> rcmdVideoList( static Future<LoadingState> rcmdVideoList(
@@ -145,10 +147,8 @@ class VideoHttp {
(!enableRcmdDynamic ? i['card_goto'] != 'picture' : true) && (!enableRcmdDynamic ? i['card_goto'] != 'picture' : true) &&
(i['args'] != null && (i['args'] != null &&
!blackMidsList.contains(i['args']['up_id']))) { !blackMidsList.contains(i['args']['up_id']))) {
String banWordForZone = GStorage.banWordForZone; if (zoneRegExp.pattern.isNotEmpty &&
if (banWordForZone.isNotEmpty && zoneRegExp.hasMatch(i['args']['rname'])) {
RegExp(banWordForZone, caseSensitive: false)
.hasMatch(i['args']['rname'])) {
continue; continue;
} }
RecVideoItemAppModel videoItem = RecVideoItemAppModel.fromJson(i); RecVideoItemAppModel videoItem = RecVideoItemAppModel.fromJson(i);
@@ -178,10 +178,8 @@ class VideoHttp {
!RecommendFilter.filterTitle(i['title']) && !RecommendFilter.filterTitle(i['title']) &&
!RecommendFilter.filterLikeRatio( !RecommendFilter.filterLikeRatio(
i['stat']['like'], i['stat']['view'])) { i['stat']['like'], i['stat']['view'])) {
String banWordForZone = GStorage.banWordForZone; if (zoneRegExp.pattern.isNotEmpty &&
if (banWordForZone.isNotEmpty && zoneRegExp.hasMatch(i['tname'])) {
RegExp(banWordForZone, caseSensitive: false)
.hasMatch(i['tname'])) {
continue; continue;
} }
list.add(HotVideoItemModel.fromJson(i)); list.add(HotVideoItemModel.fromJson(i));
@@ -1096,10 +1094,8 @@ class VideoHttp {
!RecommendFilter.filterTitle(i['title']) && !RecommendFilter.filterTitle(i['title']) &&
!RecommendFilter.filterLikeRatio( !RecommendFilter.filterLikeRatio(
i['stat']['like'], i['stat']['view'])) { i['stat']['like'], i['stat']['view'])) {
String banWordForZone = GStorage.banWordForZone; if (zoneRegExp.pattern.isNotEmpty &&
if (banWordForZone.isNotEmpty && zoneRegExp.hasMatch(i['tname'])) {
RegExp(banWordForZone, caseSensitive: false)
.hasMatch(i['tname'])) {
continue; continue;
} }
list.add(HotVideoItemModel.fromJson(i)); list.add(HotVideoItemModel.fromJson(i));

View File

@@ -37,7 +37,6 @@ abstract class ReplyController extends CommonController {
late Rx<Mode> mode = Mode.MAIN_LIST_HOT.obs; late Rx<Mode> mode = Mode.MAIN_LIST_HOT.obs;
late bool hasUpTop = false; late bool hasUpTop = false;
late final banWordForReply = GStorage.banWordForReply;
late final antiGoodsReply = GStorage.antiGoodsReply; late final antiGoodsReply = GStorage.antiGoodsReply;
// comment antifraud // comment antifraud
@@ -384,7 +383,7 @@ abstract class ReplyController extends CommonController {
type: replyType, type: replyType,
sort: ReplySortType.time.index, sort: ReplySortType.time.index,
page: 1, page: 1,
banWordForReply: '', enableFilter: false,
antiGoodsReply: false, antiGoodsReply: false,
); );
if (context.mounted.not) return; if (context.mounted.not) return;
@@ -412,7 +411,7 @@ abstract class ReplyController extends CommonController {
root: rpid ?? replyId, root: rpid ?? replyId,
pageNum: 1, pageNum: 1,
type: replyType, type: replyType,
banWordForReply: '', filterBanWord: false,
antiGoodsReply: false, antiGoodsReply: false,
); );
if (context.mounted.not) return; if (context.mounted.not) return;
@@ -433,7 +432,7 @@ abstract class ReplyController extends CommonController {
root: rpid ?? replyId, root: rpid ?? replyId,
pageNum: 1, pageNum: 1,
type: replyType, type: replyType,
banWordForReply: '', filterBanWord: false,
isCheck: true, isCheck: true,
antiGoodsReply: false, antiGoodsReply: false,
); );
@@ -470,7 +469,7 @@ https://api.bilibili.com/x/v2/reply/reply?oid=$oid&pn=1&ps=20&root=${rpid ?? rep
root: rpid ?? replyId, root: rpid ?? replyId,
pageNum: i, pageNum: i,
type: replyType, type: replyType,
banWordForReply: '', filterBanWord: false,
isCheck: true, isCheck: true,
antiGoodsReply: false, antiGoodsReply: false,
); );
@@ -505,7 +504,7 @@ https://api.bilibili.com/x/v2/reply/reply?oid=$oid&pn=1&ps=20&root=${rpid ?? rep
root: rpid ?? replyId, root: rpid ?? replyId,
pageNum: i, pageNum: i,
type: replyType, type: replyType,
banWordForReply: '', filterBanWord: false,
isCheck: true, isCheck: true,
antiGoodsReply: false, antiGoodsReply: false,
); );

View File

@@ -54,7 +54,6 @@ class DynamicDetailController extends ReplyController {
next: cursor?.next ?? $fixnum.Int64(0), next: cursor?.next ?? $fixnum.Int64(0),
mode: mode.value, mode: mode.value,
), ),
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
) )
: ReplyHttp.replyList( : ReplyHttp.replyList(
@@ -64,7 +63,6 @@ class DynamicDetailController extends ReplyController {
type: type, type: type,
sort: sortType.value.index, sort: sortType.value.index,
page: currentPage, page: currentPage,
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
); );
} }

View File

@@ -85,7 +85,6 @@ class HtmlRenderController extends ReplyController {
next: cursor?.next ?? $fixnum.Int64(0), next: cursor?.next ?? $fixnum.Int64(0),
mode: mode.value, mode: mode.value,
), ),
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
) )
: ReplyHttp.replyList( : ReplyHttp.replyList(
@@ -95,7 +94,6 @@ class HtmlRenderController extends ReplyController {
type: type, type: type,
sort: sortType.value.index, sort: sortType.value.index,
page: currentPage, page: currentPage,
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
); );
} }

View File

@@ -4,6 +4,8 @@ import 'dart:math';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart' import 'package:PiliPlus/common/widgets/refresh_indicator.dart'
show kDragContainerExtentPercentage, displacement; show kDragContainerExtentPercentage, displacement;
import 'package:PiliPlus/http/interceptor.dart'; import 'package:PiliPlus/http/interceptor.dart';
import 'package:PiliPlus/http/reply.dart';
import 'package:PiliPlus/http/video.dart';
import 'package:PiliPlus/models/common/audio_normalization.dart'; import 'package:PiliPlus/models/common/audio_normalization.dart';
import 'package:PiliPlus/models/common/dynamic_badge_mode.dart'; import 'package:PiliPlus/models/common/dynamic_badge_mode.dart';
import 'package:PiliPlus/models/common/dynamics_type.dart'; import 'package:PiliPlus/models/common/dynamics_type.dart';
@@ -2320,6 +2322,16 @@ SettingsModel getBanwordModel({
await GStorage.setting.put(key, banWord); await GStorage.setting.put(key, banWord);
setState(); setState();
SmartDialog.showToast('已保存'); SmartDialog.showToast('已保存');
if (key == SettingBoxKey.banWordForReply) {
ReplyHttp.replyRegExp =
RegExp(banWord, caseSensitive: false);
} else if (key == SettingBoxKey.banWordForRecommend) {
RecommendFilter.rcmdRegExp =
RegExp(banWord, caseSensitive: false);
} else if (key == SettingBoxKey.banWordForZone) {
VideoHttp.zoneRegExp =
RegExp(banWord, caseSensitive: false);
}
}, },
), ),
], ],

View File

@@ -23,7 +23,6 @@ class VideoReplyController extends ReplyController {
next: cursor?.next ?? $fixnum.Int64(0), next: cursor?.next ?? $fixnum.Int64(0),
mode: mode.value, mode: mode.value,
), ),
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
) )
: ReplyHttp.replyList( : ReplyHttp.replyList(
@@ -33,7 +32,6 @@ class VideoReplyController extends ReplyController {
type: ReplyType.video.index, type: ReplyType.video.index,
sort: sortType.value.index, sort: sortType.value.index,
page: currentPage, page: currentPage,
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
); );
} }

View File

@@ -169,7 +169,6 @@ class VideoReplyReplyController extends ReplyController
next: cursor?.next, next: cursor?.next,
mode: mode.value, mode: mode.value,
), ),
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
) )
: GlobalData().grpcReply : GlobalData().grpcReply
@@ -182,7 +181,6 @@ class VideoReplyReplyController extends ReplyController
next: cursor?.next, next: cursor?.next,
mode: mode.value, mode: mode.value,
), ),
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
) )
: ReplyHttp.replyReplyList( : ReplyHttp.replyReplyList(
@@ -191,7 +189,6 @@ class VideoReplyReplyController extends ReplyController
root: rpid, root: rpid,
pageNum: currentPage, pageNum: currentPage,
type: replyType.index, type: replyType.index,
banWordForReply: banWordForReply,
antiGoodsReply: antiGoodsReply, antiGoodsReply: antiGoodsReply,
); );

View File

@@ -8,7 +8,8 @@ class RecommendFilter {
static late int minLikeRatioForRecommend; static late int minLikeRatioForRecommend;
static late bool exemptFilterForFollowed; static late bool exemptFilterForFollowed;
static late bool applyFilterToRelatedVideos; static late bool applyFilterToRelatedVideos;
static late String banWords; static RegExp rcmdRegExp =
RegExp(GStorage.banWordForRecommend, caseSensitive: false);
RecommendFilter() { RecommendFilter() {
update(); update();
@@ -23,7 +24,6 @@ class RecommendFilter {
setting.get(SettingBoxKey.minDurationForRcmd, defaultValue: 0); setting.get(SettingBoxKey.minDurationForRcmd, defaultValue: 0);
minLikeRatioForRecommend = minLikeRatioForRecommend =
setting.get(SettingBoxKey.minLikeRatioForRecommend, defaultValue: 0); setting.get(SettingBoxKey.minLikeRatioForRecommend, defaultValue: 0);
banWords = setting.get(SettingBoxKey.banWordForRecommend, defaultValue: '');
exemptFilterForFollowed = exemptFilterForFollowed =
setting.get(SettingBoxKey.exemptFilterForFollowed, defaultValue: true); setting.get(SettingBoxKey.exemptFilterForFollowed, defaultValue: true);
applyFilterToRelatedVideos = setting applyFilterToRelatedVideos = setting
@@ -67,8 +67,7 @@ class RecommendFilter {
if (exemptFilterForFollowed && isFollowed == true) { if (exemptFilterForFollowed && isFollowed == true) {
return false; return false;
} }
if (banWords.isNotEmpty && if (rcmdRegExp.pattern.isNotEmpty && rcmdRegExp.hasMatch(title)) {
RegExp(banWords, caseSensitive: false).hasMatch(title)) {
return true; return true;
} }
return false; return false;