mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-23 18:37:14 +02:00
feat(YouTube Music): add support versions 7.01.53
~ 7.02.51
This commit is contained in:
parent
904f1d6357
commit
f15a5d5259
@ -10,6 +10,7 @@ import app.revanced.patches.music.misc.minimizedplayback.fingerprints.MinimizedP
|
||||
import app.revanced.patches.music.misc.minimizedplayback.fingerprints.MusicBrowserServiceFingerprint
|
||||
import app.revanced.patches.music.misc.minimizedplayback.fingerprints.PodCastConfigFingerprint
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.util.getStartsWithStringInstructionIndex
|
||||
import app.revanced.util.getStringInstructionIndex
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
@ -51,7 +52,7 @@ object MinimizedPlaybackPatch : BaseBytecodePatch(
|
||||
MusicBrowserServiceFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val targetIndex =
|
||||
getStringInstructionIndex("MBS: Return empty root for client: %s, isFullMediaBrowserEnabled: %b, is client browsable: %b, isRedAccount: %b")
|
||||
getStartsWithStringInstructionIndex("MBS: Return empty root for client: %s")
|
||||
|
||||
for (index in targetIndex downTo 0) {
|
||||
if (getInstruction(index).opcode != Opcode.INVOKE_VIRTUAL) continue
|
||||
|
@ -2,14 +2,17 @@ package app.revanced.patches.music.misc.minimizedplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.util.getStartsWithStringInstructionIndex
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MusicBrowserServiceFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("Ljava/lang/String;", "Landroid/os/Bundle;"),
|
||||
strings = listOf("MBS: Return empty root for client: %s, isFullMediaBrowserEnabled: %b, is client browsable: %b, isRedAccount: %b"),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.definingClass.endsWith("/MusicBrowserService;")
|
||||
customFingerprint = custom@{ methodDef, _ ->
|
||||
if (!methodDef.definingClass.endsWith("/MusicBrowserService;"))
|
||||
return@custom false
|
||||
|
||||
methodDef.getStartsWithStringInstructionIndex("MBS: Return empty root for client: %s") > 0
|
||||
}
|
||||
)
|
@ -10,8 +10,9 @@ object Constants {
|
||||
"6.29.58",
|
||||
"6.31.55",
|
||||
"6.33.52",
|
||||
"6.50.53",
|
||||
"6.51.53"
|
||||
"6.51.53",
|
||||
"7.01.53",
|
||||
"7.02.51",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -16,7 +16,7 @@ import app.revanced.patches.music.utils.settings.fingerprints.GoogleApiActivityF
|
||||
import app.revanced.patches.music.utils.settings.fingerprints.PreferenceFingerprint
|
||||
import app.revanced.patches.music.utils.settings.fingerprints.SettingsHeadersFragmentFingerprint
|
||||
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_UTILS_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.shared.settings.fingerprints.SharedSettingFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
@ -14,7 +14,7 @@ import app.revanced.patches.reddit.utils.resourceid.SharedResourceIdPatch.LabelA
|
||||
import app.revanced.patches.reddit.utils.settings.fingerprints.AcknowledgementsLabelBuilderFingerprint
|
||||
import app.revanced.patches.reddit.utils.settings.fingerprints.OssLicensesMenuActivityOnCreateFingerprint
|
||||
import app.revanced.patches.reddit.utils.settings.fingerprints.SettingsStatusLoadFingerprint
|
||||
import app.revanced.patches.shared.settings.fingerprints.SharedSettingFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.SharedSettingFingerprint
|
||||
import app.revanced.util.getTargetIndex
|
||||
import app.revanced.util.getWideLiteralInstructionIndex
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.shared.settings.fingerprints
|
||||
package app.revanced.patches.shared.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.shared.integrations.Constants.INTEGRATIONS_SETTING_CLASS_DESCRIPTOR
|
@ -7,8 +7,10 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.integrations.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.shared.litho.fingerprints.EmptyComponentsFingerprint
|
||||
import app.revanced.patches.shared.litho.fingerprints.LithoFilterPatchConstructorFingerprint
|
||||
import app.revanced.patches.shared.litho.fingerprints.PathBuilderFingerprint
|
||||
import app.revanced.patches.shared.litho.fingerprints.SetByteBufferFingerprint
|
||||
@ -19,6 +21,7 @@ import app.revanced.util.getTargetIndexWithFieldReferenceType
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction35c
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import java.io.Closeable
|
||||
@ -26,8 +29,8 @@ import java.io.Closeable
|
||||
@Suppress("SpellCheckingInspection", "unused")
|
||||
object LithoFilterPatch : BytecodePatch(
|
||||
setOf(
|
||||
EmptyComponentsFingerprint,
|
||||
LithoFilterPatchConstructorFingerprint,
|
||||
PathBuilderFingerprint,
|
||||
SetByteBufferFingerprint
|
||||
)
|
||||
), Closeable {
|
||||
@ -40,6 +43,13 @@ object LithoFilterPatch : BytecodePatch(
|
||||
internal lateinit var addFilter: (String) -> Unit
|
||||
private set
|
||||
|
||||
private lateinit var emptyComponentMethod: MutableMethod
|
||||
|
||||
private lateinit var emptyComponentLabel: String
|
||||
private lateinit var emptyComponentMethodName: String
|
||||
|
||||
private lateinit var pathBuilderMethodCall: String
|
||||
|
||||
private var filterCount = 0
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
@ -55,14 +65,75 @@ object LithoFilterPatch : BytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
PathBuilderFingerprint.resultOrThrow().let {
|
||||
EmptyComponentsFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
// resolves fingerprint.
|
||||
PathBuilderFingerprint.resolve(context, it.classDef)
|
||||
emptyComponentMethod = this
|
||||
emptyComponentMethodName = name
|
||||
|
||||
val emptyComponentMethodIndex = it.scanResult.patternScanResult!!.startIndex + 1
|
||||
val emptyComponentMethodReference =
|
||||
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex).reference
|
||||
val emptyComponentFieldReference =
|
||||
getInstruction<ReferenceInstruction>(emptyComponentMethodIndex + 2).reference
|
||||
|
||||
emptyComponentLabel = """
|
||||
move-object/from16 v0, p1
|
||||
invoke-static {v0}, $emptyComponentMethodReference
|
||||
move-result-object v0
|
||||
iget-object v0, v0, $emptyComponentFieldReference
|
||||
return-object v0
|
||||
"""
|
||||
}
|
||||
}
|
||||
|
||||
PathBuilderFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
// If the EmptyComponents Method and the PathBuilder Method are different,
|
||||
// new inject way is required.
|
||||
// TODO: Refactor LithoFilter patch when support for YouTube 18.29.38 ~ 19.17.41 and YT Music 6.29.58 ~ 6.51.53 is dropped.
|
||||
if (emptyComponentMethodName != name) {
|
||||
// In this case, the access modifier of the method that handles PathBuilder is 'AccessFlags.PRIVATE or AccessFlags.FINAL.
|
||||
// Methods that handle PathBuilder are invoked by methods that handle EmptyComponents.
|
||||
// 'pathBuilderMethodCall' is a reference that invokes the PathBuilder Method.
|
||||
pathBuilderMethodCall = "$definingClass->$name("
|
||||
for (i in 0 until parameters.size) {
|
||||
pathBuilderMethodCall += parameterTypes[i]
|
||||
}
|
||||
pathBuilderMethodCall += ")$returnType"
|
||||
|
||||
emptyComponentMethod.apply {
|
||||
// If the return value of the PathBuilder Method is null,
|
||||
// it means that pathBuilder has been filtered by the LithoFilterPatch.
|
||||
// (Refer comments below.)
|
||||
// Returns emptyComponents.
|
||||
for (index in implementation!!.instructions.size - 1 downTo 0) {
|
||||
val instruction = getInstruction(index)
|
||||
if ((instruction as? ReferenceInstruction)?.reference.toString() != pathBuilderMethodCall)
|
||||
continue
|
||||
|
||||
val insertRegister = getInstruction<OneRegisterInstruction>(index + 1).registerA
|
||||
val insertIndex = index + 2
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
if-nez v$insertRegister, :ignore
|
||||
""" + emptyComponentLabel,
|
||||
ExternalLabel("ignore", getInstruction(insertIndex))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// If the EmptyComponents Method and the PathBuilder Method are different,
|
||||
// PathBuilder Method's returnType cannot cast emptyComponents.
|
||||
// So just returns null value.
|
||||
emptyComponentLabel = """
|
||||
const/4 v0, 0x0
|
||||
return-object v0
|
||||
"""
|
||||
}
|
||||
|
||||
val stringBuilderIndex = getTargetIndexWithFieldReferenceType("Ljava/lang/StringBuilder;")
|
||||
val stringBuilderRegister = getInstruction<TwoRegisterInstruction>(stringBuilderIndex).registerA
|
||||
|
||||
@ -81,12 +152,8 @@ object LithoFilterPatch : BytecodePatch(
|
||||
invoke-static {v$stringBuilderRegister, v$identifierRegister, v$objectRegister}, $INTEGRATIONS_LITHO_FILER_CLASS_DESCRIPTOR->filter(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/Object;)Z
|
||||
move-result v$stringBuilderRegister
|
||||
if-eqz v$stringBuilderRegister, :filter
|
||||
move-object/from16 v0, p1
|
||||
invoke-static {v0}, $emptyComponentMethodReference
|
||||
move-result-object v0
|
||||
iget-object v0, v0, $emptyComponentFieldReference
|
||||
return-object v0
|
||||
""", ExternalLabel("filter", getInstruction(insertIndex))
|
||||
""" + emptyComponentLabel,
|
||||
ExternalLabel("filter", getInstruction(insertIndex))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
package app.revanced.patches.shared.litho.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object EmptyComponentsFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.INVOKE_STATIC_RANGE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf("Error while converting %s")
|
||||
)
|
@ -1,18 +1,11 @@
|
||||
package app.revanced.patches.shared.litho.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
/**
|
||||
* Since YouTube v19.18.41 and YT Music 7.01.53, pathBuilder is being handled by a different Method.
|
||||
*/
|
||||
internal object PathBuilderFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.INVOKE_STATIC_RANGE,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT
|
||||
),
|
||||
strings = listOf("Error while converting %s")
|
||||
strings = listOf("Number of bits must be positive")
|
||||
)
|
@ -18,7 +18,6 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMut
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@ -212,7 +211,14 @@ fun Method.getEmptyStringInstructionIndex()
|
||||
fun Method.getStringInstructionIndex(value: String) = implementation?.let {
|
||||
it.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.CONST_STRING
|
||||
&& (instruction as? BuilderInstruction21c)?.reference.toString() == value
|
||||
&& (instruction as? ReferenceInstruction)?.reference.toString() == value
|
||||
}
|
||||
} ?: -1
|
||||
|
||||
fun Method.getStartsWithStringInstructionIndex(value: String) = implementation?.let {
|
||||
it.instructions.indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.CONST_STRING
|
||||
&& (instruction as? ReferenceInstruction)?.reference.toString().startsWith(value)
|
||||
}
|
||||
} ?: -1
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user