diff --git a/app/src/main/java/me/iacn/biliroaming/CommentFilterDialog.kt b/app/src/main/java/me/iacn/biliroaming/CommentFilterDialog.kt index 125fef5737..42c36f3582 100644 --- a/app/src/main/java/me/iacn/biliroaming/CommentFilterDialog.kt +++ b/app/src/main/java/me/iacn/biliroaming/CommentFilterDialog.kt @@ -6,6 +6,7 @@ import android.view.inputmethod.EditorInfo import android.widget.* import me.iacn.biliroaming.utils.Log import me.iacn.biliroaming.utils.dp +import me.iacn.biliroaming.utils.inflateLayout class CommentFilterDialog(activity: Activity, prefs: SharedPreferences) : BaseWidgetDialog(activity) { @@ -47,6 +48,40 @@ class CommentFilterDialog(activity: Activity, prefs: SharedPreferences) : ).let { root.addView(it.first); it.second } blockAtCommentSwitch.isChecked = prefs.getBoolean("comment_filter_block_at_comment", false) + val targetCommentAuthorLevelTitle = + categoryTitle(string(R.string.target_comment_author_level_title)) + root.addView(targetCommentAuthorLevelTitle) + + val seekBarView = context.inflateLayout(R.layout.seekbar_dialog) + val currentTargetCommentAuthorLevel = + prefs.getLong("target_comment_author_level", 0L).toInt() + val tvHint = seekBarView.findViewById(R.id.tvHint).apply { + text = context.getString( + R.string.danmaku_filter_weight_hint, + currentTargetCommentAuthorLevel + ) + } + val seekBar = seekBarView.findViewById(R.id.seekBar).apply { + max = 6 + setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged( + seekBar: SeekBar?, progress: Int, fromUser: Boolean + ) { + tvHint.text = + if (progress == 0) "关闭" else context.getString( + R.string.danmaku_filter_weight_hint, + progress + ) + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) {} + override fun onStopTrackingTouch(seekBar: SeekBar?) {} + }) + progress = currentTargetCommentAuthorLevel + } + + root.addView(seekBarView) + setTitle(string(R.string.filter_comment_title)) setPositiveButton(android.R.string.ok) { _, _ -> @@ -64,6 +99,7 @@ class CommentFilterDialog(activity: Activity, prefs: SharedPreferences) : putStringSet("comment_filter_keyword_at_uid", uidGroup.getKeywords()) putBoolean("comment_filter_content_regex_mode", contentRegexMode) putBoolean("comment_filter_block_at_comment", blockAtCommentSwitch.isChecked) + putLong("target_comment_author_level", seekBar.progress.toLong()) }.apply() Log.toast(string(R.string.prefs_save_success_and_reboot)) } diff --git a/app/src/main/java/me/iacn/biliroaming/hook/ProtoBufHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/ProtoBufHook.kt index a72f79f88a..61274022f3 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/ProtoBufHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/ProtoBufHook.kt @@ -56,6 +56,7 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { sPrefs.getStringSet("comment_filter_keyword_at_upname", null).orEmpty() } val commentFilterBlockAtComment = sPrefs.getBoolean("comment_filter_block_at_comment", false) + val targetCommentAuthorLevel = sPrefs.getLong("target_comment_author_level", 0L) val purifyCampus = sPrefs.getBoolean("purify_campus", false) val blockWordSearch = sPrefs.getBoolean("block_word_search", false) val blockModules = sPrefs.getBoolean("block_modules", false) @@ -315,34 +316,48 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { } } - val needCommentFilter = hidden and (commentFilterBlockAtComment or commentFilterContents.isNotEmpty() or commentFilterAtUid.isNotEmpty() or commentFilterAtUpNames.isNotEmpty()) + val needCommentFilter = + hidden && (commentFilterBlockAtComment || commentFilterContents.isNotEmpty() || commentFilterAtUid.isNotEmpty() || commentFilterAtUpNames.isNotEmpty() || targetCommentAuthorLevel != 0L) if (needCommentFilter) { val blockAtCommentSplitRegex = Regex("\\s+") - fun filterComment(replyInfo: Any?): Boolean { - if (replyInfo == null) return true - val content = replyInfo.getObjectField("content_")!! - val message = content.getObjectFieldAs("message_") - if (commentFilterContents.isNotEmpty()) { - if (commentFilterContentRegexMode) { - if (commentFilterContentRegexes.any { it.matches(message) }) return false - } else { - if (commentFilterContents.any { message.contains(it) }) return false - } + + fun Any.validCommentAuthorLevel(): Boolean { + if (targetCommentAuthorLevel == 0L) return true + val authorLevel = getObjectField("member_")?.getObjectFieldAs("level_") ?: 6L + return authorLevel >= targetCommentAuthorLevel + } + + fun Any.validCommentContent(): Boolean { + val content = getObjectField("content_") ?: return true + val commentMessage = content.getObjectFieldAs("message_") + + val contentIsToBlock = commentFilterContents.isNotEmpty() && if (commentFilterContentRegexMode) { + commentFilterContentRegexes.any { commentMessage.contains(it) } + } else { + commentFilterContents.any { commentMessage.contains(it) } } - if (commentFilterBlockAtComment && message.trim().split(blockAtCommentSplitRegex).all { it.startsWith("@") }) return false + if (contentIsToBlock) return false + + if (commentFilterBlockAtComment && commentMessage.trim() + .split(blockAtCommentSplitRegex).all { it.startsWith("@") } + ) return false + + if (commentFilterAtUpNames.isEmpty() && commentFilterAtUid.isEmpty()) return true val atNameToMid = content.getObjectFieldAs>("atNameToMid_") - if (commentFilterAtUpNames.isNotEmpty() && atNameToMid.keys.any { it in commentFilterAtUpNames }) return false - return !(commentFilterAtUid.isNotEmpty() && atNameToMid.values.any { it in commentFilterAtUid }) + return !(atNameToMid.keys.any { it in commentFilterAtUpNames } || atNameToMid.values.any { it in commentFilterAtUid }) } + + fun Any.filterComment() = validCommentAuthorLevel() && validCommentContent() + "com.bapis.bilibili.main.community.reply.v1.MainListReply".from(mClassLoader) ?.hookAfterMethod("getRepliesList") { p -> val l = p.result as? List<*> ?: return@hookAfterMethod - p.result = l.filter { filterComment(it) } + p.result = l.filter { it?.filterComment() ?: true } } "com.bapis.bilibili.main.community.reply.v1.ReplyInfo".from(mClassLoader) ?.hookAfterMethod("getRepliesList") { p -> val l = p.result as? List<*> ?: return@hookAfterMethod - p.result = l.filter { filterComment(it) } + p.result = l.filter { it?.filterComment() ?: true } } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f905cb1ee2..1d14586a1b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -285,6 +285,7 @@ \@的用户名 \@的uid 屏蔽只含\@的评论 + 屏蔽指定等级以下用户评论 推荐封面比例 自定义首页推荐小卡(双列显示的)封面比例