Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[pull] master from yujincheng08:master #49

Open
wants to merge 43 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
7d07474
feat: KillDelayBootHook (#1553)
CodePwn2021 Nov 12, 2024
845ceff
fix: crash when searching sensitive words (#1551)
CodePwn2021 Nov 12, 2024
88bb21c
fix: comment copy on play v3.19.1+ and v7.77.0+ (#1537)
Aiden2014 Nov 12, 2024
e2bc2c3
build(deps): bump the maven-dependencies group across 1 directory wit…
dependabot[bot] Nov 12, 2024
d7f0d82
fix: initHookInfo find biliAccounts class failed on 8.18.0+ (#1555)
CodePwn2021 Nov 12, 2024
8c7fd1a
fix: home tab filter adds rules for bangumi_v2 and cinema_v2 (#1557)
CodePwn2021 Nov 13, 2024
2ee0be6
fix: PegasusHook for v8.17.0+ (#1561)
CodePwn2021 Nov 15, 2024
18116c7
fix: BangumiPlayUrlHook, BangumiSeasonHook, ProtoBufHook for v8.17.0+…
CodePwn2021 Nov 16, 2024
e45e4d5
feat: PegasusHook support viewUnite (#1564)
CodePwn2021 Nov 17, 2024
0d39ff1
fix: use viewUnite for replaceStoryVideo (#1566)
CodePwn2021 Nov 17, 2024
233a877
feat: search filter add remove relate promote (#1567)
CodePwn2021 Nov 18, 2024
05e0848
refactor: optimize code (#1569)
CodePwn2021 Nov 19, 2024
2879601
fix: more NoSuchMethodError (#1570)
CodePwn2021 Nov 19, 2024
d7e2a55
fix: incorrect method name (#1571)
CodePwn2021 Nov 20, 2024
ab8bf49
build(deps): bump the maven-dependencies group with 5 updates (#1575)
dependabot[bot] Nov 28, 2024
1e00861
build(deps): bump the maven-dependencies group across 1 directory wit…
dependabot[bot] Dec 5, 2024
1287ece
fix: custom theme & video quality & some hookinfo (#1589)
TinyHai Dec 28, 2024
90ccf96
fix: found wrong hookinfo of okhttp (#1591)
TinyHai Dec 29, 2024
8a10ca7
fix: video description can't be freely copied
TinyHai Dec 31, 2024
5c36575
fix: prefer video tab
TinyHai Dec 31, 2024
59e1d32
fix: allow download
TinyHai Dec 31, 2024
519ee2e
fix: replace b23.tv with bili2233.cn (#1598)
HinataKato Jan 1, 2025
28a4449
build(deps): bump the maven-dependencies group across 1 directory wit…
dependabot[bot] Jan 2, 2025
dde92b1
fix: force media notification styles follow the system
TinyHai Jan 2, 2025
d7ab210
fix: purify dyn video page
TinyHai Jan 2, 2025
fd11a0f
clean unused hooks in DynamicHook
TinyHai Jan 2, 2025
4c328a6
Keep b23.tv compatibility
yujincheng08 Jan 3, 2025
e065e7c
fix: show avid (#1601)
TinyHai Jan 3, 2025
af10950
feat: separately purify Live and UP in dyn all page (#1602)
TinyHai Jan 3, 2025
89c0537
fix: change the description for purify share (#1603)
HinataKato Jan 3, 2025
9dfda93
fix: crash caused by unlocking area in some cases (#1604)
TinyHai Jan 4, 2025
a222172
fix: video quality for v8.9.0+ (#1605)
TinyHai Jan 6, 2025
9ed39c2
fix: auto like
TinyHai Jan 7, 2025
3adab00
fix: remove relate video
TinyHai Jan 7, 2025
6702d38
fix: optimize the way to find selectQuality for play ver. (#1607)
TinyHai Jan 8, 2025
6ff4ddb
fix: find selectQuality for hd ver.
TinyHai Jan 8, 2025
5e46c07
fix: disable custom theme for hd ver.
TinyHai Jan 8, 2025
1f2f8bf
fix: disable try vip quality for v7.50.0+ (#1609)
TinyHai Jan 9, 2025
c0f074f
fix: crash in some cases (#1612)
TinyHai Jan 12, 2025
d0859f0
Upgrade Gradle
yujincheng08 Jan 12, 2025
5552175
build(deps): bump the maven-dependencies group with 4 updates (#1610)
dependabot[bot] Jan 12, 2025
e888312
feat: live quality (#1615)
TinyHai Jan 17, 2025
c3b2acc
fix: refine live quality (#1617)
TinyHai Jan 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: live quality (yujincheng08#1615)
- 添加设置直播默认清晰度
  • Loading branch information
TinyHai authored Jan 17, 2025
commit e8883122a2f5d3f6a31752008c5689b86a5eecbe
62 changes: 62 additions & 0 deletions app/src/main/java/me/iacn/biliroaming/BiliBiliPackage.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package me.iacn.biliroaming
import android.app.AndroidAppHelper
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.text.style.ClickableSpan
import android.text.style.LineBackgroundSpan
import android.util.SparseArray
Expand Down Expand Up @@ -168,6 +169,8 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
val playSpeedManager by Weak { mHookInfo.playSpeedManager from mClassLoader }
val continuationClass by Weak { mHookInfo.continuation.class_ from mClassLoader }
val vipQualityTrialService by Weak { mHookInfo.vipQualityTrialService.class_ from mClassLoader }
val livePlayUrlSelectUtilClass by Weak { mHookInfo.liveQuality.selectUtil.class_ from mClassLoader }
val liveRTCSourceServiceImplClass by Weak { mHookInfo.liveQuality.sourceService.class_ from mClassLoader }

// for v8.17.0+
val useNewMossFunc = instance.viewMossClass?.declaredMethods?.any {
Expand Down Expand Up @@ -332,6 +335,10 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex

fun onFeedClicked() = mHookInfo.cardClickProcessor.onFeedClicked.orNull

fun parseUriMethod() = mHookInfo.liveQuality.selectUtil.parseUri.orNull

fun switchAutoMethod() = mHookInfo.liveQuality.sourceService.switchAuto.orNull

private fun readHookInfo(context: Context): Configs.HookInfo {
try {
val hookInfoFile = File(context.cacheDir, Constant.HOOK_INFO_FILE_NAME)
Expand Down Expand Up @@ -2125,6 +2132,61 @@ class BiliBiliPackage constructor(private val mClassLoader: ClassLoader, mContex
class_ = class_ { name = serviceClass.name }
canTrial = method { name = canTrialMethod.name }
}
liveQuality = liveQuality {
val utilClass = dexHelper.findMethodUsingString(
"select 秒开 play url --codec:",
false,
-1,
-1,
null,
-1,
null,
null,
null,
true
).map {
dexHelper.decodeMethodIndex(it)?.declaringClass
}.firstOrNull() ?: return@liveQuality
val selectorDataClass = dexHelper.findMethodUsingString(
"LiveUrlSelectorData(playUrl=",
false,
-1,
-1,
null,
-1,
null,
null,
null,
true
).map {
dexHelper.decodeMethodIndex(it)?.declaringClass
}.firstOrNull() ?: return@liveQuality
val parseUriMethod = utilClass.declaredMethods.firstOrNull {
it.returnType == selectorDataClass && it.parameterCount == 1 && it.parameterTypes[0] == Uri::class.java
} ?: return@liveQuality
val switchAutoMethod = dexHelper.findMethodUsingString(
"switchAuto ",
false,
-1,
-1,
null,
-1,
null,
null,
null,
true
).map {
dexHelper.decodeMethodIndex(it)
}.firstOrNull() ?: return@liveQuality
selectUtil = livePlayUrlSelectUtil {
class_ = class_ { name = utilClass.name }
parseUri = method { name = parseUriMethod.name }
}
sourceService = liveRTCSourceServiceImpl {
class_ = class_ { name = switchAutoMethod.declaringClass.name }
switchAuto = method { name = switchAutoMethod.name }
}
}

dexHelper.close()
}
Expand Down
1 change: 1 addition & 0 deletions app/src/main/java/me/iacn/biliroaming/XposedInit.kt
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class XposedInit : IXposedHookLoadPackage, IXposedHookZygoteInit {
startHook(UposReplaceHook(lpparam.classLoader))
startHook(SpeedHook(lpparam.classLoader))
startHook(MultiWindowHook(lpparam.classLoader))
startHook(LiveQualityHook(lpparam.classLoader))
}

lpparam.processName.endsWith(":web") -> {
Expand Down
147 changes: 147 additions & 0 deletions app/src/main/java/me/iacn/biliroaming/hook/LiveQualityHook.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package me.iacn.biliroaming.hook

import android.net.Uri
import me.iacn.biliroaming.BiliBiliPackage.Companion.instance
import me.iacn.biliroaming.utils.*
import org.json.JSONArray
import org.json.JSONObject

class LiveQualityHook(classLoader: ClassLoader) : BaseHook(classLoader) {

override fun startHook() {
val liveQuality = sPrefs.getString("live_quality", "0")?.toIntOrNull() ?: 0
if (liveQuality <= 0) {
return
}

val canSwitchLiveRoom = !sPrefs.getBoolean("forbid_switch_live_room", false)

instance.retrofitResponseClass?.hookBeforeAllConstructors { param ->
val url = getRetrofitUrl(param.args[0]) ?: return@hookBeforeAllConstructors
val body = param.args[1] ?: return@hookBeforeAllConstructors

when {
instance.generalResponseClass?.isInstance(body) != true -> Unit
// 处理上下滑动切换直播间
url.startsWith("https://api.live.bilibili.com/xlive/app-interface/v2/room/recList?") && canSwitchLiveRoom -> {
val data = body.getObjectField("data") ?: return@hookBeforeAllConstructors
val info = JSONObject(instance.fastJsonClass?.callStaticMethod("toJSONString", data).toString())
if (fixLiveRoomFeedInfo(info, liveQuality)) {
body.setObjectField(
"data",
instance.fastJsonClass?.callStaticMethod(instance.fastJsonParse(), info.toString(), data.javaClass)
)
}
}
url.startsWith("https://api.live.bilibili.com/xlive/app-room/v2/index/getRoomPlayInfo?") -> {
val uri = Uri.parse(url)
val reqQn = uri.getQueryParameter("qn")
if (!reqQn.isNullOrEmpty() && reqQn != "0") {
return@hookBeforeAllConstructors
}
val data = body.getObjectField("data") ?: return@hookBeforeAllConstructors
val info = JSONObject(instance.fastJsonClass?.callStaticMethod("toJSONString", data).toString())
if (fixRoomPlayInfo(info, liveQuality)) {
body.setObjectField(
"data",
instance.fastJsonClass?.callStaticMethod(instance.fastJsonParse(), info.toString(), data.javaClass)
)
}
}
}
}

instance.liveRTCSourceServiceImplClass?.hookBeforeAllMethods(instance.switchAutoMethod()) { param ->
val mode = param.args[0] as? Enum<*> ?: return@hookBeforeAllMethods
if (mode.ordinal == 2) { // AUTO
param.result = null
}
}

instance.livePlayUrlSelectUtilClass?.hookBeforeMethod(
instance.parseUriMethod(),
Uri::class.java
) { param ->
val originalUri = param.args[0] as Uri
if (!originalUri.isLive()) {
return@hookBeforeMethod
}

val newQuality = findQuality(
JSONArray(originalUri.getQueryParameter("accept_quality")),
liveQuality
).toString()

param.args[0] = originalUri.replaceQuery { name, oldVal ->
when {
"current_qn" == name -> newQuality
"current_quality" == name -> newQuality
name.endsWith("current_qn") -> "0"
else -> oldVal
}
}
}
}

private fun Uri.isLive(): Boolean {
return scheme in arrayOf("http", "https")
&& host == "live.bilibili.com"
&& pathSegments.firstOrNull()?.all { it.isDigit() } == true
}

private fun findQuality(acceptQuality: JSONArray, expectQuality: Int): Int {
val acceptQnList = acceptQuality.asSequence<Int>().sorted().toList()
val max = acceptQnList.max()
val min = acceptQnList.min()
return when {
expectQuality > max -> max
expectQuality < min -> min
else -> acceptQnList.first { it >= expectQuality }
}
}

private fun Uri.replaceQuery(replacer: (String, String) -> String?): Uri {
val newBuilder = buildUpon().clearQuery()
for (name in queryParameterNames) {
val newValue = replacer(name, getQueryParameter(name) ?: "")
newValue?.let { newBuilder.appendQueryParameter(name, it) }
}
return newBuilder.build()
}

private fun fixLiveRoomFeedInfo(info: JSONObject, expectQuality: Int): Boolean {
val feedList = info.optJSONArray("list") ?: return false
feedList.iterator().forEach { feedData ->
val newQuality = findQuality(feedData.getJSONArray("accept_quality"), expectQuality)
feedData.put("current_qn", newQuality)
feedData.put("current_quality", newQuality)
}
return true
}

private fun fixRoomPlayInfo(info: JSONObject, expectQuality: Int): Boolean {
val playUrlInfo = info.optJSONObject("playurl_info") ?: return false
val playUrlObj = playUrlInfo.getJSONObject("playurl")
playUrlObj.getJSONArray("stream").iterator().forEach { stream ->
stream.getJSONArray("format").iterator().forEach { format ->
format.getJSONArray("codec").iterator().asSequence().run {
firstOrNull { codec -> fixCodec(codec, expectQuality, true) }
?: firstOrNull { codec -> fixCodec(codec, expectQuality, false) }
}
}
}
return true
}

private fun fixCodec(codec: JSONObject, expectQuality: Int, strict: Boolean): Boolean {
val newQuality = findQuality(codec.getJSONArray("accept_qn"), expectQuality)
if (strict && newQuality != expectQuality) {
return false
}
val oldQn = codec.getInt("current_qn")
if (oldQn != newQuality) {
codec.put("current_qn", newQuality)
}
return true
}
}
16 changes: 16 additions & 0 deletions app/src/main/proto/me/iacn/biliroaming/configs.proto
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,21 @@ message VipQualityTrialService {
optional Method canTrial = 2;
}

message LivePlayUrlSelectUtil {
optional Class class = 1;
optional Method parseUri = 2;
}

message LiveRTCSourceServiceImpl {
optional Class class = 1;
optional Method switchAuto = 2;
}

message LiveQuality {
optional LivePlayUrlSelectUtil selectUtil = 1;
optional LiveRTCSourceServiceImpl sourceService = 2;
}

message HookInfo {
int64 last_update_time = 1;
optional MapIds map_ids = 2;
Expand Down Expand Up @@ -340,4 +355,5 @@ message HookInfo {
optional QualityStrategyProvider qualityStrategyProvider = 95;
optional Continuation continuation = 96;
optional VipQualityTrialService vipQualityTrialService = 97;
optional LiveQuality liveQuality = 98;
}
20 changes: 20 additions & 0 deletions app/src/main/res/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,26 @@
<item>120</item>
<item>127</item>
</string-array>
<string-array name="live_quality_entries">
<item>默认</item>
<item>流畅</item>
<item>高清</item>
<item>超清</item>
<item>蓝光</item>
<item>原画</item>
<item>4K</item>
<item>杜比</item>
</string-array>
<string-array name="live_quality_values">
<item>0</item>
<item>80</item>
<item>150</item>
<item>250</item>
<item>400</item>
<item>10000</item>
<item>20000</item>
<item>30000</item>
</string-array>
<string-array name="full_screen_quality_entries">
<item>默认</item>
<item>240P</item>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@
<string name="half_screen_quality_summary">设置视频半屏播放时的清晰度,设置后会大幅降低视频的首次播放加载速度,旧版播放器(半屏时进度条在框内)仅支持跟随全屏清晰度,需开启解锁番剧限制选项</string>
<string name="full_screen_quality_title">视频全屏清晰度</string>
<string name="full_screen_quality_summary">设置视频全屏播放时默认的清晰度,当播放器画质选项为自动时此选项不生效,需开启解锁番剧限制选项</string>
<string name="live_quality_title">直播清晰度</string>
<string name="live_quality_summary">设置进入直播间的默认清晰度,若不存在指定清晰度,则会取最接近的清晰度</string>
<string name="block_comment_guide_title">屏蔽评论引导</string>
<string name="block_comment_guide_summary">屏蔽视频详情页及评论页的评论引导提示</string>
<string name="disable_auto_refresh_title">禁止首页自动刷新</string>
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/res/xml/prefs_setting.xml
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,14 @@
android:summary="@string/full_screen_quality_summary"
android:title="@string/full_screen_quality_title" />

<ListPreference
android:defaultValue="0"
android:entries="@array/live_quality_entries"
android:entryValues="@array/live_quality_values"
android:key="live_quality"
android:summary="@string/live_quality_summary"
android:title="@string/live_quality_title"/>

<SwitchPreference
android:key="block_comment_guide"
android:summary="@string/block_comment_guide_summary"
Expand Down