From 2ee0be6a3583490f8c35cd48926e86e49ca76fb0 Mon Sep 17 00:00:00 2001 From: "Hydrogen.P" <77036672+CodePwn2021@users.noreply.github.com> Date: Sat, 16 Nov 2024 07:03:58 +0800 Subject: [PATCH 1/4] fix: PegasusHook for v8.17.0+ (#1561) --- .../me/iacn/biliroaming/hook/PegasusHook.kt | 81 ++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt index 365786d62c..820eaccead 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt @@ -514,6 +514,28 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { param.result.callMethod("ensureListIsMutable") param.result.callMethodAs>("getListList").filter() } + // v8.17.0+ + instance.viewMossClass?.hookAfterMethod("executeView", instance.viewReqClass) { param -> + param.result ?: return@hookAfterMethod + if (removeRelatePromote && removeRelateOnlyAv && removeRelateNothing) { + param.result.callMethod("clearRelates") + param.result.callMethod("clearPagination") + return@hookAfterMethod + } + param.result.callMethod("ensureRelatesIsMutable") + param.result.callMethodAs>("getRelatesList").filter() + } + instance.viewMossClass?.hookAfterMethod( + "executeRelatesFeed", + "com.bapis.bilibili.app.view.v1.RelatesFeedReq" + ) { param -> + param.result ?: return@hookAfterMethod + param.result.callMethod("ensureListIsMutable") + param.result.callMethodAs>("getListList").filter() + } + + + instance.viewUniteMossClass?.run { hookAfterMethod("view", instance.viewUniteReqClass) { param -> param.result ?: return@hookAfterMethod @@ -543,6 +565,35 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { callMethodAs>("getRelatesList").filterUnite() } } + // v8.17.0+ + hookAfterMethod("executeView", instance.viewUniteReqClass) { param -> + param.result ?: return@hookAfterMethod + param.result.callMethod("getTab")?.run { + callMethod("ensureTabModuleIsMutable") + callMethodAs>("getTabModuleList").map { originalTabModules -> + if (!originalTabModules.callMethodAs("hasIntroduction")) return@map + originalTabModules.callMethodAs("getIntroduction").run { + callMethod("ensureModulesIsMutable") + callMethodAs>("getModulesList").map { module -> + if (!module.callMethodAs("hasRelates")) return@map + module.callMethodAs("getRelates").run { + callMethod("ensureCardsIsMutable") + callMethodAs>("getCardsList").filterUnite() + } + } + } + } + } + } + hookAfterMethod( + "executeRelatesFeed", + "com.bapis.bilibili.app.viewunite.v1.RelatesFeedReq" + ) { param -> + param.result?.run { + callMethod("ensureRelatesIsMutable") + callMethodAs>("getRelatesList").filterUnite() + } + } } instance.cardClickProcessorClass?.declaredMethods @@ -588,6 +639,8 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { param.result = null } + + fun MutableList.filterPopular() = removeIf { when (it.callMethod("getItemCase")?.toString()) { "SMALL_COVER_V5" -> { @@ -625,7 +678,6 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { param.args[0].setObjectField("lastParam_", popularDataVersion) param.args[0].setLongField("idx_", popularDataCount) } - instance.popularClass?.hookAfterMethod( "index", "com.bapis.bilibili.app.show.popular.v1.PopularResultReq" @@ -635,5 +687,32 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { param.result.callMethod("ensureItemsIsMutable") param.result.callMethodAs>("getItemsList").filterPopular() } + + // v8.17.0+ + instance.popularClass?.hookBeforeMethod( + "executeIndex", + "com.bapis.bilibili.app.show.popular.v1.PopularResultReq" + ) { param -> + param.args ?: return@hookBeforeMethod + + val idx = param.args[0].getLongFieldOrNull("idx_") + if (idx == null || idx == 0L) { + popularDataCount = 0 + popularDataVersion = "" + return@hookBeforeMethod + } + + param.args[0].setObjectField("lastParam_", popularDataVersion) + param.args[0].setLongField("idx_", popularDataCount) + } + instance.popularClass?.hookAfterMethod( + "executeIndex", + "com.bapis.bilibili.app.show.popular.v1.PopularResultReq" + ) { param -> + param.result ?: return@hookAfterMethod + + param.result.callMethod("ensureItemsIsMutable") + param.result.callMethodAs>("getItemsList").filterPopular() + } } } From 18116c7b1cd1634427ee46295c3ab4fee3811d07 Mon Sep 17 00:00:00 2001 From: "Hydrogen.P" <77036672+CodePwn2021@users.noreply.github.com> Date: Sat, 16 Nov 2024 19:38:58 +0800 Subject: [PATCH 2/4] fix: BangumiPlayUrlHook, BangumiSeasonHook, ProtoBufHook for v8.17.0+ (#1562) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v8.17.0+达到勉强能用级别,仍然有不完善的地方(选集切其他弹不支持观看) --- .../biliroaming/hook/BangumiPlayUrlHook.kt | 73 +++++++ .../biliroaming/hook/BangumiSeasonHook.kt | 40 ++++ .../me/iacn/biliroaming/hook/ProtoBufHook.kt | 196 ++++++++++++++++++ 3 files changed, 309 insertions(+) diff --git a/app/src/main/java/me/iacn/biliroaming/hook/BangumiPlayUrlHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/BangumiPlayUrlHook.kt index 4e0c51f7f4..04d4e42b15 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/BangumiPlayUrlHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/BangumiPlayUrlHook.kt @@ -268,6 +268,79 @@ class BangumiPlayUrlHook(classLoader: ClassLoader) : BaseHook(classLoader) { param.result = purifyViewInfo(response) } } + // v8.17.0+ + hookBeforeMethod( + "executePlayView", + "com.bapis.bilibili.pgc.gateway.player.v2.PlayViewReq" + ) { param -> + val request = param.args[0] + // if getDownload == 1 -> flv download + // if getDownload == 2 -> dash download + // if qn == 0, we are querying available quality + // else we are downloading + // if fnval == 0 -> flv download + // thus fix download will set qn = 0 and set fnval to max + isDownload = sPrefs.getBoolean("allow_download", false) + && request.callMethodAs("getDownload") >= 1 + if (isDownload) { + if (!sPrefs.getBoolean("fix_download", false) + || request.callMethodAs("getFnval") <= 1 + ) { + request.callMethod("setFnval", MAX_FNVAL) + request.callMethod("setFourk", true) + } + request.callMethod("setDownload", 0) + } else if (halfScreenQuality == 1 || fullScreenQuality != 0) { + request.callMethod("setFnval", MAX_FNVAL) + request.callMethod("setFourk", true) + if (halfScreenQuality == 1 && qnApplied.compareAndSet(false, true)) { + defaultQn?.let { request.callMethod("setQn", it) } + } + } + } + hookAfterMethod( + "executePlayView", + "com.bapis.bilibili.pgc.gateway.player.v2.PlayViewReq" + ) { param -> + // th: + // com.bilibili.lib.moss.api.BusinessException: 抱歉您所使用的平台不可观看! + // com.bilibili.lib.moss.api.BusinessException: 啥都木有 + // connection err <- should skip because of cache: + // throwable: com.bilibili.lib.moss.api.NetworkException + if (instance.networkExceptionClass?.isInstance(param.throwable) == true) + return@hookAfterMethod + val request = param.args[0] + val response = + param.result ?: "com.bapis.bilibili.pgc.gateway.player.v2.PlayViewReply" + .on(mClassLoader).new() + if (needProxy(response)) { + try { + val serializedRequest = request.callMethodAs("toByteArray") + val req = PlayViewReq.parseFrom(serializedRequest) + val seasonId = req.seasonId.toString().takeIf { it != "0" } + ?: lastSeasonInfo["season_id"] ?: "0" + val (thaiSeason, thaiEp) = getSeasonLazy(seasonId, req.epId) + val content = getPlayUrl(reconstructQuery(req, response, thaiEp)) + content?.let { + Log.toast("已从代理服务器获取播放地址\n如加载缓慢或黑屏,可去漫游设置中测速并设置 UPOS") + param.result = reconstructResponse( + req, response, it, isDownload, thaiSeason, thaiEp + ) + } + ?: throw CustomServerException(mapOf("未知错误" to "请检查哔哩漫游设置中解析服务器设置。")) + } catch (e: CustomServerException) { + param.result = showPlayerError( + response, + "请求解析服务器发生错误(点此查看更多)\n${e.message}" + ) + Log.toast("请求解析服务器发生错误: ${e.message}", alsoLog = true) + } + } else if (isDownload) { + param.result = fixDownloadProto(response) + } else if (blockBangumiPageAds) { + param.result = purifyViewInfo(response) + } + } } instance.playerMossClass?.run { var isDownload = false diff --git a/app/src/main/java/me/iacn/biliroaming/hook/BangumiSeasonHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/BangumiSeasonHook.kt index 0c8b9768ae..6e6e3bd705 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/BangumiSeasonHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/BangumiSeasonHook.kt @@ -330,6 +330,16 @@ class BangumiSeasonHook(classLoader: ClassLoader) : BaseHook(classLoader) { param.result = (param.method as Method).returnType.callStaticMethod("parseFrom", serializedReply) } + // v8.17.0+ + instance.viewMossClass?.hookAfterMethod("execView", instance.viewReqClass) { param -> + param.result?.let { return@hookAfterMethod } + val serializedRequest = param.args[0].callMethodAs("toByteArray") + val req = ViewReq.parseFrom(serializedRequest) + val reply = fixViewProto(req) + val serializedReply = reply?.toByteArray() ?: return@hookAfterMethod + param.result = + (param.method as Method).returnType.callStaticMethod("parseFrom", serializedReply) + } instance.viewUniteMossClass?.hookAfterMethod( "view", "com.bapis.bilibili.app.viewunite.v1.ViewReq" @@ -360,6 +370,36 @@ class BangumiSeasonHook(classLoader: ClassLoader) : BaseHook(classLoader) { fixViewProto(response, supplement) } + // v8.17.0+ + instance.viewUniteMossClass?.hookAfterMethod( + "executeView", "com.bapis.bilibili.app.viewunite.v1.ViewReq" + ) { param -> + if (instance.networkExceptionClass?.isInstance(param.throwable) == true) return@hookAfterMethod + val response = param.result + if (response == null) { + val req = param.args[0].callMethodAs("toByteArray").let { + ViewUniteReq.parseFrom(it) + } + val av = (if (req.hasAid()) req.aid.takeIf { it != 0L } else if (req.hasBvid()) bv2av(req.bvid) else null)?.toString() + fixViewProto(req, av)?.toByteArray()?.let { + param.result = + "com.bapis.bilibili.app.viewunite.v1.ViewReply".from(mClassLoader) + ?.callStaticMethod("parseFrom", it) + } ?: Log.toast("解锁失败!", force = true) + return@hookAfterMethod + } + val supplementAny = response.callMethod("getSupplement") + val typeUrl = supplementAny?.callMethodAs("getTypeUrl") + // Only handle pgc video + if (param.result != null && typeUrl != PGC_ANY_MODEL_TYPE_URL) { + return@hookAfterMethod + } + val supplement = + supplementAny?.callMethod("getValue")?.callMethodAs("toByteArray") + ?.let { ViewPgcAny.parseFrom(it) } ?: viewPgcAny {} + + fixViewProto(response, supplement) + } val urlHook: Hooker = fun(param) { val redirectUrl = param.thisObject.getObjectFieldAs("redirectUrl") 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 464f569149..f99fcea2bf 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/ProtoBufHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/ProtoBufHook.kt @@ -117,6 +117,40 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { ?.callMethod("clearLabel") } } + // v8.17.0+ + instance.viewMossClass?.hookAfterMethod("executeView", instance.viewReqClass) { param -> + param.result ?: return@hookAfterMethod + val aid = param.result.callMethod("getArc") + ?.callMethodAs("getAid") ?: -1L + val like = param.result.callMethod("getReqUser") + ?.callMethodAs("getLike") ?: -1 + AutoLikeHook.detail = aid to like + BangumiPlayUrlHook.qnApplied.set(false) + if (unlockPlayLimit) + param.result.callMethod("getConfig") + ?.callMethod("setShowListenButton", true) + if (blockCommentGuide) { + param.result.runCatchingOrNull { + callMethod("getLikeCustom") + ?.callMethod("clearLikeComment") + callMethod("getReplyPreface") + ?.callMethod("clearBadgeType") + } + } + if (hidden && removeHonor) { + param.result.callMethod("clearHonor") + } + if (hidden && removeUgcSeason) { + param.result.callMethod("clearUgcSeason") + } + if (hidden && blockLiveOrder) { + param.result.callMethod("clearLiveOrderInfo") + } + if (hidden && removeUpVipLabel) { + param.result.callMethod("getOwnerExt")?.callMethod("getVip") + ?.callMethod("clearLabel") + } + } if (hidden && removeCmdDms) { instance.viewMossClass?.hookAfterMethod( @@ -140,6 +174,28 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { instance.dmMossClass?.hookAfterMethod( "dmView", instance.dmViewReqClass, ) { it.result?.removeCmdDms() } + // v8.17.0+ + instance.viewMossClass?.hookAfterMethod( + "executeViewProgress", + "com.bapis.bilibili.app.view.v1.ViewProgressReq" + ) { param -> + param.result?.callMethod("setVideoGuide", videoGuideClass?.new()) + } + instance.viewUniteMossClass?.hookAfterMethod( + "executeViewProgress", + "com.bapis.bilibili.app.viewunite.v1.ViewProgressReq" + ) { param -> + param.result?.run { + callMethod("clearDm") + callMethod("getVideoGuide")?.callMethod("clearContractCard") + } + } + instance.viewMossClass?.replaceMethod( + "executeTFInfo", "com.bapis.bilibili.app.view.v1.TFInfoReq" + ) { null } + instance.dmMossClass?.hookAfterMethod( + "executeDmView", instance.dmViewReqClass, + ) { it.result?.removeCmdDms() } } if (hidden && purifySearch) { "com.bapis.bilibili.app.interfaces.v1.SearchMoss".hookAfterMethod( @@ -149,6 +205,14 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { ) { param -> param.result = null } + // v8.17.0+ + "com.bapis.bilibili.app.interfaces.v1.SearchMoss".hookAfterMethod( + mClassLoader, + "executeDefaultWords", + "com.bapis.bilibili.app.interfaces.v1.DefaultWordsReq" + ) { param -> + param.result = null + } } if (hidden && blockWordSearch) { "com.bapis.bilibili.main.community.reply.v1.Content".hookAfterMethod( @@ -176,6 +240,14 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { ) { it.result?.callMethod("clearPools") } + // v8.17.0+ + "com.bapis.bilibili.app.resource.v1.ModuleMoss".hookAfterMethod( + mClassLoader, + "executeList", + "com.bapis.bilibili.app.resource.v1.ListReq" + ) { + it.result?.callMethod("clearPools") + } } if (hidden && blockUpperRecommendAd) { "com.bapis.bilibili.ad.v1.SourceContentDto".from(mClassLoader) @@ -295,6 +367,103 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { } } } + // v8.17.0+ + "com.bapis.bilibili.main.community.reply.v1.ReplyMoss".hookBeforeMethod( + mClassLoader, + "executeMainList", + "com.bapis.bilibili.main.community.reply.v1.MainListReq", + instance.mossResponseHandlerClass + ) { param -> + val type = param.args[0].callMethodAs("getType") + if (hidden && blockVideoComment && type == 1L) { + val reply = mainListReplyClass?.new()?.apply { + val subjectControl = callMethod("getSubjectControl") + val emptyPage = emptyPageV1Class?.new()?.also { + subjectControl?.callMethod("setEmptyPage", it) + } + emptyPage?.callMethod( + "setImageUrl", + "https://i0.hdslb.com/bfs/app-res/android/img_holder_forbid_style1.webp" + ) + textV1Class?.new()?.apply { + callMethod("setRaw", "评论区已由漫游屏蔽") + textStyleV1Class?.new()?.apply { + callMethod("setFontSize", 14) + callMethod("setTextDayColor", "#FF61666D") + callMethod("setTextNightColor", "#FFA2A7AE") + }?.let { + callMethod("setStyle", it) + } + }?.let { + emptyPage?.callMethod("addTexts", it) + } + } + param.args[1].callMethod("onNext", reply) + param.result = null + return@hookBeforeMethod + } + if (!blockCommentGuide) return@hookBeforeMethod + param.args[1] = param.args[1].mossResponseHandlerProxy { reply -> + reply?.runCatchingOrNull { + callMethod("getSubjectControl")?.run { + callMethod("clearEmptyBackgroundTextPlain") + callMethod("clearEmptyBackgroundTextHighlight") + callMethod("clearEmptyBackgroundUri") + callMethod("getEmptyPage")?.let { page -> + page.callMethod("clearLeftButton") + page.callMethod("clearRightButton") + page.callMethodAs>("getTextsList").takeIf { it.size > 1 } + ?.let { + page.callMethod("clearTexts") + page.callMethod("addTexts", it.first().apply { + callMethod("setRaw", "还没有评论哦") + }) + } + } + } + } + } + } + "com.bapis.bilibili.main.community.reply.v2.ReplyMoss".from(mClassLoader) + ?.hookBeforeMethod( + "executeSubjectDescription", + "com.bapis.bilibili.main.community.reply.v2.SubjectDescriptionReq", + instance.mossResponseHandlerClass + ) { param -> + val defaultText = textV2Class?.new()?.apply { + val tipStr = if (hidden && blockVideoComment) { + "评论区已由漫游屏蔽" + } else { + "还没有评论哦" + } + callMethod("setRaw", tipStr) + textStyleV2Class?.new()?.apply { + callMethod("setFontSize", 14) + callMethod("setTextDayColor", "#FF61666D") + callMethod("setTextNightColor", "#FFA2A7AE") + }?.let { + callMethod("setStyle", it) + } + } ?: return@hookBeforeMethod + param.args[1] = param.args[1].mossResponseHandlerProxy { reply -> + reply?.runCatchingOrNull { + callMethod("getEmptyPage")?.run { + callMethod("clearLeftButton") + callMethod("clearRightButton") + callMethod("ensureTextsIsMutable") + callMethodAs>("getTextsList").run { + clear() + add(defaultText) + } + if (!(hidden && blockVideoComment)) return@run + callMethod( + "setImageUrl", + "https://i0.hdslb.com/bfs/app-res/android/img_holder_forbid_style1.webp" + ) + } + } + } + } } val needSearchFilter = hidden and (searchFilterContents.isNotEmpty() or searchFilterUid.isNotEmpty() or searchFilterUpNames.isNotEmpty()) if (needSearchFilter) { @@ -402,6 +571,33 @@ class ProtoBufHook(classLoader: ClassLoader) : BaseHook(classLoader) { } } } + // v8.17.0+ + instance.viewUniteMossClass?.hookAfterMethod( + "executeView", instance.viewUniteReqClass + ) { param -> + if (instance.networkExceptionClass?.isInstance(param.throwable) == true) return@hookAfterMethod + param.result ?: return@hookAfterMethod + + if (blockViewPageAds) { + param.result.callMethod("clearCm") + } + + param.result.callMethod("getTab")?.run { + callMethod("ensureTabModuleIsMutable") + val tabModuleList = callMethodAs>("getTabModuleList") + tabModuleList.removeAll { + blockVideoComment && it.callMethodAs("hasReply") + } + if (!(blockViewPageAds || removeHonor)) return@run + tabModuleList.map { + if (!it.callMethodAs("hasIntroduction")) return@map + it.callMethodAs("getIntroduction").run { + callMethod("ensureModulesIsMutable") + callMethodAs>("getModulesList").filter() + } + } + } + } if (!sPrefs.getBoolean("replace_story_video", false)) return val disableBooleanValue = "com.bapis.bilibili.app.distribution.BoolValue".from(mClassLoader)?.callStaticMethod("getDefaultInstance") ?: return From e45e4d581c01347493561dc7c3428ac566aff364 Mon Sep 17 00:00:00 2001 From: "Hydrogen.P" <77036672+CodePwn2021@users.noreply.github.com> Date: Sun, 17 Nov 2024 08:14:37 +0800 Subject: [PATCH 3/4] feat: PegasusHook support viewUnite (#1564) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持viewUnite的视频下方推荐过滤 --- .../me/iacn/biliroaming/hook/PegasusHook.kt | 82 ++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt index 820eaccead..1d3222ee44 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/PegasusHook.kt @@ -115,6 +115,10 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { else it < hideLowPlayCountLimit } } + private fun isLowCountVideoUnite(count: Long): Boolean { + if (hideLowPlayCountLimit == 0L) return false + return count < hideLowPlayCountLimit + } // 屏蔽指定播放时长 private fun durationVideo(obj: Any): Boolean { @@ -126,6 +130,13 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { return true return hideShortDurationLimit != 0 && duration < hideShortDurationLimit } + private fun durationVideoUnite(duration: Long): Boolean { + if (hideLongDurationLimit == 0 && hideShortDurationLimit == 0) + return false + if (hideLongDurationLimit != 0 && duration > hideLongDurationLimit) + return true + return hideShortDurationLimit != 0 && duration < hideShortDurationLimit + } private fun isContainsBlockKwd(obj: Any): Boolean { // 屏蔽标题关键词 @@ -196,6 +207,46 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { return false } + private fun isContainsBlockKwdUnite(card: Any): Boolean { + if (card.callMethodAs("hasBasicInfo")) { + card.callMethodAs("getBasicInfo").let { basicInfo -> + // 屏蔽标题关键词 + if (kwdFilterTitleList.isNotEmpty()) { + val title = basicInfo.callMethodAs("getTitle") + if (kwdFilterTitleRegexMode && title.isNotEmpty()) { + if (kwdFilterTitleRegexes.any { title.contains(it) }) + return true + } else if (title.isNotEmpty()) { + if (kwdFilterTitleList.any { title.contains(it) }) + return true + } + } + + basicInfo.callMethodAs("getAuthor").let { author -> + // 屏蔽UID + if (kwdFilterUidList.isNotEmpty()) { + val uid = author.callMethodAs("getMid") + if (uid != 0L && kwdFilterUidList.any { it == uid }) + return true + } + + // 屏蔽UP主 + if (kwdFilterUpnameList.isNotEmpty()) { + val upName = author.callMethodAs("getTitle") + if (kwdFilterUpnameRegexMode && upName.isNotEmpty()) { + if (kwdFilterUpnameRegexes.any { upName.contains(it) }) + return true + } else if (upName.isNotEmpty()) { + if (kwdFilterUpnameList.any { upName.contains(it) }) + return true + } + } + } + } + } + return false + } + private fun ArrayList.appendReasons() = forEach { item -> val title = item.getObjectFieldAs("title").orEmpty() val rcmdReason = item.runCatchingOrNull { @@ -486,6 +537,7 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { fun MutableList.filterUnite() = removeAll { val allowTypeList = mutableListOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + var shouldFiltered = false allowTypeList.removeAll { digit -> (removeRelateOnlyAv && digit != 1) || (removeRelatePromote && digit in listOf( 3, // Resource, like mall @@ -494,7 +546,35 @@ class PegasusHook(classLoader: ClassLoader) : BaseHook(classLoader) { 10 // SPECIAL )) } - removeRelateNothing || it.callMethodAs("getRelateCardTypeValue") !in allowTypeList + // av filter + if (applyToRelate) { + if (it.callMethodAs("hasAv")) { + it.callMethodAs("getAv").let { av -> + val duration = av.callMethodAs("getDuration") + if (durationVideoUnite(duration)) { + shouldFiltered = true + return@let + } + if (av.callMethodAs("hasStat")) { + av.callMethodAs("getStat").let { stat -> + if (stat.callMethodAs("hasVt")) { + stat.callMethodAs("getVt").let { vt -> + if (isLowCountVideoUnite(vt.callMethodAs("getValue"))) { + shouldFiltered = true + return@let + } + } + } + } + } + } + if (isContainsBlockKwdUnite(it)) { + shouldFiltered = true + } + } + // todo: support rcmd + } + removeRelateNothing || it.callMethodAs("getRelateCardTypeValue") !in allowTypeList || shouldFiltered } instance.viewMossClass?.hookAfterMethod("view", instance.viewReqClass) { param -> param.result ?: return@hookAfterMethod From 0d39ff1558f18ef432832e0683a8438b0c5bf4af Mon Sep 17 00:00:00 2001 From: "Hydrogen.P" <77036672+CodePwn2021@users.noreply.github.com> Date: Sun, 17 Nov 2024 20:33:54 +0800 Subject: [PATCH 4/4] fix: use viewUnite for replaceStoryVideo (#1566) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 替换竖版视频功能使用新版activity,从而解决评论区图片打不开的问题 --- .../biliroaming/hook/StartActivityHook.kt | 47 +++++++++++++++++-- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/me/iacn/biliroaming/hook/StartActivityHook.kt b/app/src/main/java/me/iacn/biliroaming/hook/StartActivityHook.kt index d6cf3db60c..af9854bbb2 100644 --- a/app/src/main/java/me/iacn/biliroaming/hook/StartActivityHook.kt +++ b/app/src/main/java/me/iacn/biliroaming/hook/StartActivityHook.kt @@ -11,8 +11,21 @@ import me.iacn.biliroaming.utils.hookBeforeAllMethods import me.iacn.biliroaming.utils.hookBeforeMethod import me.iacn.biliroaming.utils.packageName import me.iacn.biliroaming.utils.sPrefs +import me.iacn.biliroaming.utils.toJSONObject +import kotlin.math.floor class StartActivityHook(classLoader: ClassLoader) : BaseHook(classLoader) { + + private fun fixIntentUri(original: Uri): Uri { + val fixedUri = Uri.parse(original.toString().replace("bilibili://story/", "bilibili://united_video/")).buildUpon() + .clearQuery() + .appendQueryParameter("from_spmid", original.getQueryParameter("from_spmid")) + .appendQueryParameter("aid", original.path?.split("/")?.last() ?: "") + .appendQueryParameter("bvid", "") + .build() + return fixedUri + } + override fun startHook() { "tv.danmaku.bili.ui.intent.IntentHandlerActivity".hookBeforeMethod(mClassLoader, "onCreate", Bundle::class.java) { param -> val a = param.thisObject as Activity @@ -27,11 +40,35 @@ class StartActivityHook(classLoader: ClassLoader) : BaseHook(classLoader) { false ) && uri.startsWith("bilibili://story/") ) { - intent.component = ComponentName( - intent.component?.packageName ?: packageName, - "com.bilibili.video.videodetail.VideoDetailsActivity" - ) - intent.data = Uri.parse(uri.replace("bilibili://story/", "bilibili://video/")) + intent.data?.let { + try { + val cid = intent.data?.getQueryParameter("player_preload").toJSONObject().getLong("cid") + intent.data = fixIntentUri(Uri.parse(intent.dataString)) + // fix extra + val pre = Uri.parse(intent.dataString).buildUpon().clearQuery().build().toString() + val aid = pre.split("/").last().toLong() + intent.removeExtra("player_preload") + intent.putExtra("player_preload", floor(Math.random()*1000000000).toInt().toString()) + intent.putExtra("blrouter.targeturl", pre) + intent.putExtra("blrouter.pagename", "bilibili://united_video/") + intent.putExtra("jumpFrom", 7) + intent.putExtra("", aid) + intent.putExtra("aid", aid) + intent.putExtra("cid", cid) + intent.putExtra("bvid", "") + intent.putExtra("from", 7) + intent.putExtra("blrouter.targeturl", pre) + intent.putExtra("blrouter.matchrule", "bilibili://united_video/") + // fix component + intent.component = ComponentName( + intent.component?.packageName ?: packageName, + "com.bilibili.ship.theseus.detail.UnitedBizDetailsActivity" + ) + } catch (e: Exception) { + Log.e("replaceStoryVideo fix intent failed!!!") + Log.e(e) + } + } } if (sPrefs.getBoolean("force_browser", false)) { if (intent.component?.className?.endsWith("MWebActivity") == true &&