Compare commits

..

10 Commits

Author SHA1 Message Date
semantic-release-bot
32c5fa4d04 chore(release): 4.9.0-dev.6 [skip ci]
# [4.9.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.5...v4.9.0-dev.6) (2024-06-02)

### Bug Fixes

* **YouTube - Spoof client:** Restore playback speed menu when spoofing to an iOS client ([61401c9](61401c9ea4))
2024-06-02 15:46:01 +00:00
oSumAtrIX
61401c9ea4 fix(YouTube - Spoof client): Restore playback speed menu when spoofing to an iOS client 2024-06-02 17:43:41 +02:00
semantic-release-bot
cd42182d6b chore(release): 4.9.0-dev.5 [skip ci]
# [4.9.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.4...v4.9.0-dev.5) (2024-06-01)

### Features

* **YouTube:** Support version `19.12`, `19.13`, `19.14`, `19.15` and `19.16` ([#3239](https://github.com/ReVanced/revanced-patches/issues/3239)) ([868f51d](868f51d992))
2024-06-01 18:10:28 +00:00
LisoUseInAIKyrios
868f51d992 feat(YouTube): Support version 19.12, 19.13, 19.14, 19.15 and 19.16 (#3239)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-06-01 22:08:09 +04:00
semantic-release-bot
efbe314e0d chore(release): 4.9.0-dev.4 [skip ci]
# [4.9.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.3...v4.9.0-dev.4) (2024-06-01)

### Features

* **Messenger:** Add `Hide inbox subtabs` patch ([#3163](https://github.com/ReVanced/revanced-patches/issues/3163)) ([a331f0a](a331f0a30b))
2024-06-01 17:27:18 +00:00
seaque
a331f0a30b feat(Messenger): Add Hide inbox subtabs patch (#3163)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-06-01 19:25:14 +02:00
semantic-release-bot
2f54118b39 chore(release): 4.9.0-dev.3 [skip ci]
# [4.9.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.2...v4.9.0-dev.3) (2024-06-01)

### Features

* **YouTube Music:** Support version `7.03` ([#3272](https://github.com/ReVanced/revanced-patches/issues/3272)) ([6c25c95](6c25c95747))
2024-06-01 15:54:45 +00:00
LisoUseInAIKyrios
6c25c95747 feat(YouTube Music): Support version 7.03 (#3272) 2024-06-01 19:52:43 +04:00
semantic-release-bot
ad07efbd4a chore(release): 4.9.0-dev.2 [skip ci]
# [4.9.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.1...v4.9.0-dev.2) (2024-06-01)

### Bug Fixes

* **YouTube - Spoof client:** Allow swipe gestures to enter/exit fullscreen when spoofing with `Android VR` client ([#3259](https://github.com/ReVanced/revanced-patches/issues/3259)) ([ea1deb6](ea1deb630e))
2024-06-01 09:31:24 +00:00
KAZI MMT
ea1deb630e fix(YouTube - Spoof client): Allow swipe gestures to enter/exit fullscreen when spoofing with Android VR client (#3259) 2024-06-01 13:29:24 +04:00
90 changed files with 877 additions and 251 deletions

View File

@@ -1,3 +1,38 @@
# [4.9.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.5...v4.9.0-dev.6) (2024-06-02)
### Bug Fixes
* **YouTube - Spoof client:** Restore playback speed menu when spoofing to an iOS client ([95f290f](https://github.com/ReVanced/revanced-patches/commit/95f290f1139cc8679beecac53c623847668f885e))
# [4.9.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.4...v4.9.0-dev.5) (2024-06-01)
### Features
* **YouTube:** Support version `19.12`, `19.13`, `19.14`, `19.15` and `19.16` ([#3239](https://github.com/ReVanced/revanced-patches/issues/3239)) ([99b07e0](https://github.com/ReVanced/revanced-patches/commit/99b07e0e18574668f36bb3c962c8d11222114be4))
# [4.9.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.3...v4.9.0-dev.4) (2024-06-01)
### Features
* **Messenger:** Add `Hide inbox subtabs` patch ([#3163](https://github.com/ReVanced/revanced-patches/issues/3163)) ([24e4ebd](https://github.com/ReVanced/revanced-patches/commit/24e4ebd77ad0f349b479926bf3983b72c2683496))
# [4.9.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.2...v4.9.0-dev.3) (2024-06-01)
### Features
* **YouTube Music:** Support version `7.03` ([#3272](https://github.com/ReVanced/revanced-patches/issues/3272)) ([d1ceca3](https://github.com/ReVanced/revanced-patches/commit/d1ceca39984f7933b28d81802d04bb3ead327595))
# [4.9.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.9.0-dev.1...v4.9.0-dev.2) (2024-06-01)
### Bug Fixes
* **YouTube - Spoof client:** Allow swipe gestures to enter/exit fullscreen when spoofing with `Android VR` client ([#3259](https://github.com/ReVanced/revanced-patches/issues/3259)) ([5114900](https://github.com/ReVanced/revanced-patches/commit/5114900b1b5572c04ba6759eedab77f0a934b058))
# [4.9.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.8.3...v4.9.0-dev.1) (2024-05-31)

View File

@@ -277,20 +277,26 @@ public final class app/revanced/patches/memegenerator/misc/pro/UnlockProVersionP
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/messenger/ads/inbox/patch/HideInboxAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/ads/inbox/patch/HideInboxAdsPatch;
public final class app/revanced/patches/messenger/inbox/HideInboxAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inbox/HideInboxAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/messenger/inputfield/patch/DisableSwitchingEmojiToStickerPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inputfield/patch/DisableSwitchingEmojiToStickerPatch;
public final class app/revanced/patches/messenger/inbox/HideInboxSubtabsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inbox/HideInboxSubtabsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/messenger/inputfield/patch/DisableTypingIndicatorPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inputfield/patch/DisableTypingIndicatorPatch;
public final class app/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
public final class app/revanced/patches/messenger/inputfield/DisableTypingIndicatorPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inputfield/DisableTypingIndicatorPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
@@ -1883,7 +1889,11 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
public static final fun getException (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/patch/PatchException;
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I
public static synthetic fun indexOfFirstInstruction$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;)I
public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I

View File

@@ -1,4 +1,4 @@
org.gradle.parallel = true
org.gradle.caching = true
kotlin.code.style = official
version = 4.9.0-dev.1
version = 4.9.0-dev.6

View File

@@ -1,21 +1,21 @@
package app.revanced.patches.messenger.ads.inbox.patch
package app.revanced.patches.messenger.inbox
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.messenger.ads.inbox.fingerprints.LoadInboxAdsFingerprint
import app.revanced.patches.messenger.inbox.fingerprints.LoadInboxAdsFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide inbox ads",
description = "Hides ads in inbox.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")]
compatiblePackages = [CompatiblePackage("com.facebook.orca")],
)
@Suppress("unused")
object HideInboxAdsPatch : BytecodePatch(
setOf(LoadInboxAdsFingerprint)
setOf(LoadInboxAdsFingerprint),
) {
override fun execute(context: BytecodeContext) {
LoadInboxAdsFingerprint.result?.mutableMethod?.apply {
@@ -23,4 +23,3 @@ object HideInboxAdsPatch : BytecodePatch(
} ?: throw LoadInboxAdsFingerprint.exception
}
}

View File

@@ -0,0 +1,24 @@
package app.revanced.patches.messenger.inbox
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.messenger.inbox.fingerprints.CreateInboxSubTabsFingerprint
import app.revanced.util.exception
@Patch(
name = "Hide inbox subtabs",
description = "Hides Home and Channels tabs between active now tray and chats.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")],
)
@Suppress("unused")
object HideInboxSubtabsPatch : BytecodePatch(
setOf(CreateInboxSubTabsFingerprint),
) {
// Set InboxSubtabsItemSupplierImplementation boolean attribute to false.
override fun execute(context: BytecodeContext) = CreateInboxSubTabsFingerprint.result?.mutableMethod
?.replaceInstruction(2, "const/4 v0, 0x0")
?: throw CreateInboxSubTabsFingerprint.exception
}

View File

@@ -0,0 +1,23 @@
package app.revanced.patches.messenger.inbox.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
import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue
internal object CreateInboxSubTabsFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID,
),
customFingerprint = { methodDef, classDef ->
methodDef.name == "run" && classDef.fields.any any@{ field ->
if (field.name != "__redex_internal_original_name") return@any false
(field.initialValue as? StringEncodedValue)?.value == "InboxSubtabsItemSupplierImplementation\$onSubscribe\$1"
}
},
)

View File

@@ -1,4 +1,4 @@
package app.revanced.patches.messenger.ads.inbox.fingerprints
package app.revanced.patches.messenger.inbox.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
@@ -8,11 +8,10 @@ internal object LoadInboxAdsFingerprint : MethodFingerprint(
returnType = "V",
strings = listOf(
"ads_load_begin",
"inbox_ads_fetch_start"
"inbox_ads_fetch_start",
),
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
customFingerprint = { methodDef, _ ->
methodDef.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;"
}
},
)

View File

@@ -1,6 +1,5 @@
package app.revanced.patches.messenger.inputfield.patch
package app.revanced.patches.messenger.inputfield
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
@@ -8,16 +7,17 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.messenger.inputfield.fingerprints.SwitchMessangeInputEmojiButtonFingerprint
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch(
name = "Disable switching emoji to sticker",
description = "Disables switching from emoji to sticker search mode in message input field.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")]
compatiblePackages = [CompatiblePackage("com.facebook.orca")],
)
@Suppress("unused")
object DisableSwitchingEmojiToStickerPatch : BytecodePatch(
setOf(SwitchMessangeInputEmojiButtonFingerprint)
setOf(SwitchMessangeInputEmojiButtonFingerprint),
) {
override fun execute(context: BytecodeContext) {
SwitchMessangeInputEmojiButtonFingerprint.result?.let {
@@ -28,7 +28,7 @@ object DisableSwitchingEmojiToStickerPatch : BytecodePatch(
replaceInstruction(
setStringIndex,
"const-string v$targetRegister, \"expression\""
"const-string v$targetRegister, \"expression\"",
)
}
} ?: throw SwitchMessangeInputEmojiButtonFingerprint.exception

View File

@@ -1,22 +1,22 @@
package app.revanced.patches.messenger.inputfield.patch
package app.revanced.patches.messenger.inputfield
import app.revanced.util.exception
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.messenger.inputfield.fingerprints.SendTypingIndicatorFingerprint
import app.revanced.util.exception
@Patch(
name = "Disable typing indicator",
description = "Disables the indicator while typing a message.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")]
compatiblePackages = [CompatiblePackage("com.facebook.orca")],
)
@Suppress("unused")
object DisableTypingIndicatorPatch : BytecodePatch(
setOf(SendTypingIndicatorFingerprint)
){
setOf(SendTypingIndicatorFingerprint),
) {
override fun execute(context: BytecodeContext) {
SendTypingIndicatorFingerprint.result?.mutableMethod?.replaceInstruction(0, "return-void")
?: throw SendTypingIndicatorFingerprint.exception

View File

@@ -11,7 +11,18 @@ import app.revanced.util.exception
@Patch(
name = "Hide music video ads",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
],
)
@Suppress("unused")
object HideMusicVideoAds : BytecodePatch(

View File

@@ -11,7 +11,18 @@ import com.android.tools.smali.dexlib2.Opcode
@Patch(
description = "Adds more audio codec options. The new audio codecs usually result in better audio quality.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
]
)
@Deprecated("This patch is no longer needed as the feature is now enabled by default.")
object CodecsUnlockPatch : BytecodePatch(

View File

@@ -11,7 +11,18 @@ import app.revanced.util.exception
@Patch(
name = "Enable exclusive audio playback",
description = "Enables the option to play audio without video.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
]
)
@Suppress("unused")
object EnableExclusiveAudioPlayback : BytecodePatch(

View File

@@ -13,7 +13,18 @@ import app.revanced.patches.music.interaction.permanentrepeat.fingerprints.Repea
@Patch(
name = "Permanent repeat",
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
],
use = false
)
@Suppress("unused")
@@ -23,7 +34,7 @@ object PermanentRepeatPatch : BytecodePatch(
override fun execute(context: BytecodeContext) {
RepeatTrackFingerprint.result?.let {
val startIndex = it.scanResult.patternScanResult!!.endIndex
val repeatIndex = startIndex + 3
val repeatIndex = startIndex + 1
it.mutableMethod.apply {
addInstructionsWithLabels(

View File

@@ -6,17 +6,16 @@ import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object RepeatTrackFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L", "L"),
listOf(
Opcode.CHECK_CAST,
Opcode.INVOKE_INTERFACE,
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ
)
),
strings = listOf("w_st")
)

View File

@@ -12,7 +12,18 @@ import app.revanced.util.exception
name = "Permanent shuffle",
description = "Permanently remember your shuffle preference " +
"even if the playlist ends or another track is played.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
],
use = false,
)
@Suppress("unused")

View File

@@ -13,7 +13,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch(
name = "Hide category bar",
description = "Hides the category bar at the top of the homepage.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
],
use = false,
)
@Suppress("unused")

View File

@@ -13,7 +13,18 @@ import app.revanced.util.exception
@Patch(
name = "Minimized playback",
description = "Unlocks options for picture-in-picture and background playback.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
]
)
@Suppress("unused")
object MinimizedPlaybackPatch : BytecodePatch(

View File

@@ -16,7 +16,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch(
name = "Hide 'Get Music Premium' label",
description = "Hides the \"Get Music Premium\" label from the account menu and settings.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
]
)
@Suppress("unused")
object HideGetPremiumPatch : BytecodePatch(

View File

@@ -22,7 +22,18 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Patch(
name = "Remove upgrade button",
description = "Removes the upgrade tab from the pivot bar.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")],
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
]
)
@Suppress("unused")
object RemoveUpgradeButtonPatch : BytecodePatch(

View File

@@ -12,7 +12,18 @@ import app.revanced.patches.music.misc.androidauto.fingerprints.CheckCertificate
@Patch(
name = "Bypass certificate checks",
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.",
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
compatiblePackages = [
CompatiblePackage(
"com.google.android.apps.youtube.music",
[
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
]
)
]
)
@Suppress("unused")
object BypassCertificateChecksPatch : BytecodePatch(setOf(CheckCertificateFingerprint)) {

View File

@@ -23,7 +23,18 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
mainActivityOnCreateFingerprint = MusicActivityOnCreateFingerprint,
integrationsPatchDependency = IntegrationsPatch::class,
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
compatiblePackages = setOf(CompatiblePackage("com.google.android.apps.youtube.music")),
compatiblePackages = setOf(
CompatiblePackage(
"com.google.android.apps.youtube.music",
setOf(
"6.45.54",
"6.51.53",
"7.01.53",
"7.02.52",
"7.03.52",
)
)
),
fingerprints = setOf(
ServiceCheckFingerprint,
GooglePlayUtilityFingerprint,

View File

@@ -11,7 +11,7 @@ import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.Ba
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused")
@@ -68,7 +68,7 @@ object SpoofClientPatch : BaseSpoofClientPatch(
// Reddit messed up and does not append a redirect uri to the authorization url to old.reddit.com/login.
// Replace old.reddit.com with ssl.reddit.com to fix this.
BuildAuthorizationStringFingerprint.result!!.mutableMethod.apply {
val index = indexOfFirstInstruction {
val index = indexOfFirstInstructionOrThrow {
getReference<StringReference>()?.contains("old.reddit.com") == true
}

View File

@@ -11,7 +11,7 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnClearDisplayEventFingerprint
import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnRenderFirstFrameFingerprint
import app.revanced.util.exception
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
@@ -34,7 +34,7 @@ object RememberClearDisplayPatch : BytecodePatch(
OnClearDisplayEventFingerprint.result?.mutableMethod?.let {
// region Hook the "Clear display" configuration save event to remember the state of clear display.
val isEnabledIndex = it.indexOfFirstInstruction { opcode == Opcode.IGET_BOOLEAN } + 1
val isEnabledIndex = it.indexOfFirstInstructionOrThrow { opcode == Opcode.IGET_BOOLEAN } + 1
val isEnabledRegister = it.getInstruction<Instruction22c>(isEnabledIndex - 1).registerA
it.addInstructions(

View File

@@ -18,7 +18,7 @@ import app.revanced.patches.tiktok.misc.integrations.IntegrationsPatch
import app.revanced.patches.tiktok.misc.settings.SettingsPatch
import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint
import app.revanced.util.exception
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -81,16 +81,16 @@ object DownloadsPatch : BytecodePatch(
},
// Change the download path patch.
DownloadPathParentFingerprint to {
val targetIndex = indexOfFirstInstruction { opcode == Opcode.INVOKE_STATIC }
val targetIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_STATIC }
val downloadUriMethod = context
.toMethodWalker(this)
.nextMethod(targetIndex, true)
.getMethod() as MutableMethod
val firstIndex = downloadUriMethod.indexOfFirstInstruction {
val firstIndex = downloadUriMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && ((this as Instruction35c).reference as MethodReference).name == "<init>"
}
val secondIndex = downloadUriMethod.indexOfFirstInstruction {
val secondIndex = downloadUriMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_STATIC && ((this as Instruction35c).reference as MethodReference).returnType.contains(
"Uri"
)

View File

@@ -14,6 +14,7 @@ import app.revanced.patches.tiktok.interaction.speed.fingerprints.SetSpeedFinger
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -38,7 +39,7 @@ object PlaybackSpeedPatch : BytecodePatch(
SetSpeedFingerprint.result?.let { onVideoSwiped ->
// Remember the playback speed of the current video.
GetSpeedFingerprint.result?.mutableMethod?.apply {
val injectIndex = indexOfFirstInstruction { getReference<MethodReference>()?.returnType == "F" } + 2
val injectIndex = indexOfFirstInstructionOrThrow { getReference<MethodReference>()?.returnType == "F" } + 2
val register = getInstruction<Instruction11x>(injectIndex - 1).registerA
addInstruction(

View File

@@ -44,7 +44,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -38,7 +38,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -43,7 +43,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -31,7 +31,12 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -37,7 +37,12 @@ import app.revanced.util.resultOrThrow
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -42,7 +42,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -38,7 +38,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
],

View File

@@ -44,10 +44,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43", // 19.12.x has an issue with opening YT using external links,
// and the app then crashes if double tap to skip forward/back is immediately used.
// The stack trace shows a call coming from integrations SwipeController,
// but it may be a bug in YT itself as other target versions do not have this issue.
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -42,7 +42,12 @@ import app.revanced.util.exception
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
],

View File

@@ -41,7 +41,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -13,11 +13,12 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.shared.fingerprints.LayoutConstructorFingerprint
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfIdResourceOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
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.reference.MethodReference
@Patch(
@@ -52,6 +53,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
@@ -60,6 +66,10 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object HideAutoplayButtonPatch : BytecodePatch(
setOf(LayoutConstructorFingerprint),
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;"
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
@@ -67,33 +77,27 @@ object HideAutoplayButtonPatch : BytecodePatch(
SwitchPreference("revanced_hide_autoplay_button"),
)
LayoutConstructorFingerprint.result?.mutableMethod?.apply {
val layoutGenMethodInstructions = implementation!!.instructions
LayoutConstructorFingerprint.resultOrThrow().mutableMethod.apply {
val constIndex = indexOfIdResourceOrThrow("autonav_toggle")
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
// resolve the offsets of where to insert the branch instructions and ...
val insertIndex = indexOfIdResourceOrThrow("autonav_preview_stub")
// where to branch away
val branchIndex =
layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1)
.indexOfFirst {
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
} + 2
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction
// can be clobbered because this register is overwritten after the injected code
val clobberRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// Add a conditional branch around the code that inflates and adds the auto repeat button.
val gotoIndex = indexOfFirstInstructionOrThrow(constIndex) {
val parameterTypes = getReference<MethodReference>()?.parameterTypes
opcode == Opcode.INVOKE_VIRTUAL &&
parameterTypes?.size == 2 &&
parameterTypes.first() == "Landroid/view/ViewStub;"
} + 1
addInstructionsWithLabels(
insertIndex,
constIndex,
"""
invoke-static {}, Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;->isButtonShown()Z
move-result v$clobberRegister
if-eqz v$clobberRegister, :hidden
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->hideAutoPlayButton()Z
move-result v$constRegister
if-nez v$constRegister, :hidden
""",
ExternalLabel("hidden", jumpInstruction),
ExternalLabel("hidden", getInstruction(gotoIndex)),
)
} ?: throw LayoutConstructorFingerprint.exception
}
}
}

View File

@@ -42,7 +42,12 @@ import com.android.tools.smali.dexlib2.Opcode
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -19,7 +19,7 @@ import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -56,6 +56,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
@@ -111,7 +116,7 @@ object NavigationButtonsPatch : BytecodePatch(
// Hide navigation button labels.
CreatePivotBarFingerprint.result?.mutableMethod?.apply {
val setTextIndex = indexOfFirstInstruction {
val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText"
}

View File

@@ -46,7 +46,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -40,7 +40,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -43,7 +43,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -36,7 +36,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -36,7 +36,12 @@ import app.revanced.util.exception
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -23,7 +23,6 @@ import app.revanced.patches.youtube.misc.navigation.NavigationBarHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@@ -59,7 +58,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
@@ -164,20 +168,21 @@ object HideLayoutComponentsPatch : BytecodePatch(
// region Mix playlists
ParseElementFromBufferFingerprint.resultOrThrow().let { result ->
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex
val startIndex = result.scanResult.patternScanResult!!.startIndex
result.mutableMethod.apply {
val conversionContextRegister =
getInstruction<TwoRegisterInstruction>(consumeByteBufferIndex - 2).registerA
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD
val freeRegister = "v0"
val byteArrayParameter = "p3"
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
addInstructionsWithLabels(
consumeByteBufferIndex,
startIndex + 1,
"""
invoke-static {v$conversionContextRegister, v$byteBufferRegister}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v0 # Conveniently same register happens to be free.
if-nez v0, :return_empty_component
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result $freeRegister
if-nez $freeRegister, :return_empty_component
const/4 $freeRegister, 0x0 # Restore register, required for 19.16
""",
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
)

View File

@@ -4,7 +4,11 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object ParseElementFromBufferFingerprint : MethodFingerprint(
parameters = listOf("L","L","[B", "L","L"),
opcodes = listOf(Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT),
strings = listOf("Failed to parse Element")
parameters = listOf("L", "L", "[B", "L", "L"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT
),
strings = listOf("Failed to parse Element") // String is a partial match.
)

View File

@@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -41,7 +41,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -38,7 +38,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -43,7 +43,12 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -55,6 +55,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -35,7 +35,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -36,7 +36,12 @@ import app.revanced.util.exception
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -37,7 +37,12 @@ import app.revanced.util.exception
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -32,7 +32,12 @@ import org.w3c.dom.Element
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -31,7 +31,7 @@ import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAni
import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@@ -66,7 +66,12 @@ import com.android.tools.smali.dexlib2.iface.reference.TypeReference
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]
@@ -142,11 +147,10 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply {
// Find the instruction for creating the text data object.
val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type
val insertIndex = indexOfFirstInstruction {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.NEW_INSTANCE &&
getReference<TypeReference>()?.type == textDataClassType
}
if (insertIndex < 0) throw PatchException("Could not find data creation instruction")
val tempRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// Find the instruction that sets the span to an instance field.
@@ -335,7 +339,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
realTimeUpdateTextViewMethod
).forEach { insertMethod ->
insertMethod.apply {
val setTextIndex = indexOfFirstInstruction {
val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText"
}

View File

@@ -41,7 +41,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -37,7 +37,12 @@ import app.revanced.util.exception
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -52,6 +52,11 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -40,7 +40,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.misc.resources.AddResourcesPatch
@@ -15,7 +14,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@@ -46,7 +45,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]
@@ -67,12 +71,11 @@ object DisableResumingShortsOnStartupPatch : BytecodePatch(
)
UserWasInShortsFingerprint.result?.mutableMethod?.apply {
val listenableInstructionIndex = indexOfFirstInstruction {
val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
getReference<MethodReference>()?.name == "isDone"
}
if (listenableInstructionIndex < 0) throw PatchException("Could not find instruction index")
val originalInstructionRegister = getInstruction<FiveRegisterInstruction>(listenableInstructionIndex).registerC
val freeRegister = getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA

View File

@@ -45,7 +45,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
)
)
]

View File

@@ -52,7 +52,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -63,7 +63,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -41,7 +41,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -36,7 +36,12 @@ import app.revanced.util.exception
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -10,18 +10,15 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.AddResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildInitPlaybackRequestFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildPlayerRequestURIFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SetPlayerRequestClientTypeFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
@@ -63,17 +60,29 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
)
object SpoofClientPatch : BytecodePatch(
setOf(
// Client type spoof.
BuildInitPlaybackRequestFingerprint,
BuildPlayerRequestURIFingerprint,
SetPlayerRequestClientTypeFingerprint,
CreatePlayerRequestBodyFingerprint,
CreatePlayerRequestBodyWithModelFingerprint,
// Player gesture config.
PlayerGestureConfigSyntheticFingerprint,
// Player speed menu item.
CreatePlaybackSpeedMenuItemFingerprint,
),
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
@@ -87,7 +96,7 @@ object SpoofClientPatch : BytecodePatch(
SettingsPatch.PreferenceScreen.MISC.addPreferences(
PreferenceScreen(
key = "revanced_spoof_client_screen",
sorting = Sorting.UNSORTED,
sorting = PreferenceScreen.Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_spoof_client"),
SwitchPreference("revanced_spoof_client_use_ios"),
@@ -162,15 +171,14 @@ object SpoofClientPatch : BytecodePatch(
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
val instructions = it.mutableMethod.getInstructions()
// The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
instructions.subList(
getClientModelIndex,
instructions.size,
).find { instruction ->
instruction.opcode == Opcode.IPUT_OBJECT
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientModelField")
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) {
opcode == Opcode.IPUT_OBJECT
}
it.mutableMethod.getInstruction(index).getReference<FieldReference>()
?: throw PatchException("Could not find clientInfoClientModelField")
}
// endregion
@@ -243,5 +251,56 @@ object SpoofClientPatch : BytecodePatch(
// endregion
// region Fix player gesture if spoofing to iOS.
PlayerGestureConfigSyntheticFingerprint.resultOrThrow().let {
val endIndex = it.scanResult.patternScanResult!!.endIndex
val downAndOutLandscapeAllowedIndex = endIndex - 3
val downAndOutPortraitAllowedIndex = endIndex - 9
arrayOf(
downAndOutLandscapeAllowedIndex,
downAndOutPortraitAllowedIndex,
).forEach { index ->
val gestureAllowedMethod = context.toMethodWalker(it.mutableMethod)
.nextMethod(index, true)
.getMethod() as MutableMethod
gestureAllowedMethod.apply {
val isAllowedIndex = getInstructions().lastIndex
val isAllowed = getInstruction<OneRegisterInstruction>(isAllowedIndex).registerA
addInstructions(
isAllowedIndex,
"""
invoke-static { v$isAllowed }, $INTEGRATIONS_CLASS_DESCRIPTOR->enablePlayerGesture(Z)Z
move-result v$isAllowed
""",
)
}
}
}
// endregion
// Fix playback speed menu item if spoofing to iOS.
CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let {
val shouldCreateMenuIndex = it.scanResult.patternScanResult!!.endIndex
it.mutableMethod.apply {
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
addInstructions(
shouldCreateMenuIndex,
"""
invoke-static { v$shouldCreateMenuRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceCreatePlaybackSpeedMenu(Z)Z
move-result v$shouldCreateMenuRegister
""",
)
}
}
// endregion
}
}

View File

@@ -0,0 +1,22 @@
package app.revanced.patches.youtube.misc.fix.playback.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 CreatePlaybackSpeedMenuItemFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V",
parameters = listOf("[L", "F"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT, // Return value controls the creation of the playback speed menu item.
Opcode.IF_EQZ, // If the return value is false, the playback speed menu item is not created.
),
)

View File

@@ -0,0 +1,49 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal object PlayerGestureConfigSyntheticFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Ljava/lang/Object;"),
opcodes = listOf(
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutLandscapeAllowed.
Opcode.MOVE_RESULT,
Opcode.CHECK_CAST,
Opcode.IPUT_BOOLEAN,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutPortraitAllowed.
Opcode.MOVE_RESULT,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID,
),
customFingerprint = { methodDef, classDef ->
fun indexOfDownAndOutAllowedInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" &&
reference.parameterTypes.isEmpty() &&
reference.returnType == "Z"
}
// This method is always called "a" because this kind of class always has a single method.
methodDef.name == "a" && classDef.methods.count() == 2 &&
indexOfDownAndOutAllowedInstruction(methodDef) >= 0
},
)

View File

@@ -52,6 +52,11 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
"19.09.38",
"19.10.39",
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
),
),
),

View File

@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.links.fingerprints.ABUriParserFingerprint
import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch(
@@ -38,27 +38,32 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
]
)
]
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
)
@Suppress("unused")
object BypassURLRedirectsPatch : BytecodePatch(
setOf(ABUriParserFingerprint, HTTPUriParserFingerprint)
setOf(ABUriParserFingerprint, HTTPUriParserFingerprint),
) {
override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference("revanced_bypass_url_redirects")
SwitchPreference("revanced_bypass_url_redirects"),
)
mapOf(
ABUriParserFingerprint to 7, // Offset to Uri.parse.
HTTPUriParserFingerprint to 0 // Offset to Uri.parse.
HTTPUriParserFingerprint to 0, // Offset to Uri.parse.
).map { (fingerprint, offset) ->
(fingerprint.result ?: throw fingerprint.exception) to offset
fingerprint.resultOrThrow() to offset
}.forEach { (result, offset) ->
result.mutableMethod.apply {
val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset
@@ -67,11 +72,11 @@ object BypassURLRedirectsPatch : BytecodePatch(
replaceInstruction(
insertIndex,
"invoke-static {v$uriStringRegister}," +
"Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" +
"->" +
"parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;"
"Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" +
"->" +
"parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;",
)
}
}
}
}
}

View File

@@ -42,7 +42,12 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -20,10 +20,14 @@ internal object ABUriParserFingerprint : MethodFingerprint(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT,
Opcode.CHECK_CAST
Opcode.CHECK_CAST,
),
customFingerprint = { methodDef, classDef ->
// This method is always called "a" because this kind of class always has a single method.
methodDef.name == "a" && classDef.methods.count() == 3
}
)
customFingerprint = custom@{ methodDef, classDef ->
// This method is always called "a" because this kind of class always has a single (non synthetic) method.
if (methodDef.name != "a") return@custom false
val count = classDef.methods.count()
count == 2 || count == 3
},
)

View File

@@ -10,20 +10,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.*
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
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.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import java.io.Closeable
@Patch(
@@ -108,11 +106,10 @@ object LithoFilterPatch : BytecodePatch(
val emptyComponentFieldIndex = builderMethodIndex + 2
bytesToComponentContextMethod.mutableMethod.apply {
val insertHookIndex = indexOfFirstInstruction {
val insertHookIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;"
} + 1
if (insertHookIndex <= 0) throw PatchException("Could not find insert index")
// region Get free registers that this patch uses.
// Registers are overwritten right after they are used in this patch, therefore free to clobber.

View File

@@ -13,7 +13,6 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsParentFingerprint
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch
@@ -25,6 +24,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
name = "Minimized playback",
description = "Unlocks options for picture-in-picture and background playback.",
dependencies = [
MinimizedPlaybackResourcePatch::class,
IntegrationsPatch::class,
PlayerTypeHookPatch::class,
VideoInformationPatch::class,
@@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]
@@ -56,7 +61,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
object MinimizedPlaybackPatch : BytecodePatch(
setOf(
MinimizedPlaybackManagerFingerprint,
MinimizedPlaybackSettingsParentFingerprint,
MinimizedPlaybackSettingsFingerprint,
KidsMinimizedPlaybackPolicyControllerFingerprint
)
) {
@@ -82,11 +87,6 @@ object MinimizedPlaybackPatch : BytecodePatch(
} ?: throw MinimizedPlaybackManagerFingerprint.exception
// Enable minimized playback option in YouTube settings
MinimizedPlaybackSettingsParentFingerprint.result ?: throw MinimizedPlaybackSettingsParentFingerprint.exception
MinimizedPlaybackSettingsFingerprint.resolve(
context,
MinimizedPlaybackSettingsParentFingerprint.result!!.classDef
)
MinimizedPlaybackSettingsFingerprint.result?.apply {
val booleanCalls = method.implementation!!.instructions.withIndex()
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }

View File

@@ -0,0 +1,17 @@
package app.revanced.patches.youtube.misc.minimizedplayback
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
@Patch(
dependencies = [ResourceMappingPatch::class],
)
internal object MinimizedPlaybackResourcePatch : ResourcePatch() {
internal var prefBackgroundAndOfflineCategoryId: Long = -1
override fun execute(context: ResourceContext) {
prefBackgroundAndOfflineCategoryId = ResourceMappingPatch["string", "pref_background_and_offline_category"]
}
}

View File

@@ -1,11 +1,12 @@
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.MinimizedPlaybackResourcePatch
import app.revanced.util.patch.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
internal object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
@@ -16,8 +17,7 @@ internal object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.IF_NEZ,
Opcode.GOTO,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST
Opcode.GOTO
),
literalSupplier = { MinimizedPlaybackResourcePatch.prefBackgroundAndOfflineCategoryId }
)

View File

@@ -1,15 +0,0 @@
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
/**
* Class fingerprint for [MinimizedPlaybackSettingsFingerprint]
*/
internal object MinimizedPlaybackSettingsParentFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "I",
parameters = listOf(),
strings = listOf("BiometricManager", "Failure in canAuthenticate(). FingerprintManager was null.")
)

View File

@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.navigation.fingerprints.*
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@@ -121,7 +121,7 @@ object NavigationBarHookPatch : BytecodePatch(
// Insert before the first ViewGroup method call after inflating,
// so this works regardless which layout is used.
ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply {
val instructionIndex = indexOfFirstInstruction {
val instructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL && getReference<MethodReference>()?.name == "setLayoutDirection"
}

View File

@@ -43,7 +43,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
]
)
]

View File

@@ -27,7 +27,12 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],

View File

@@ -2,12 +2,12 @@ package app.revanced.patches.youtube.video.videoqualitymenu
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch
@@ -23,7 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
IntegrationsPatch::class,
RestoreOldVideoQualityMenuResourcePatch::class,
LithoFilterPatch::class,
RecyclerViewTreeHookPatch::class
RecyclerViewTreeHookPatch::class,
],
compatiblePackages = [
CompatiblePackage(
@@ -47,20 +47,25 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36",
"19.09.38",
"19.10.39",
"19.11.43"
]
)
]
"19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
],
),
],
)
@Suppress("unused")
object RestoreOldVideoQualityMenuPatch : BytecodePatch(
setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint)
setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint),
) {
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;"
"Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;"
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;"
"Lapp/revanced/integrations/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;"
override fun execute(context: BytecodeContext) {
// region Patch for the old type of the video quality menu.
@@ -75,31 +80,30 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
addInstruction(
checkCastIndex + 1,
"invoke-static { v$listViewRegister }, " +
"$INTEGRATIONS_CLASS_DESCRIPTOR->" +
"showOldVideoQualityMenu(Landroid/widget/ListView;)V"
"$INTEGRATIONS_CLASS_DESCRIPTOR->" +
"showOldVideoQualityMenu(Landroid/widget/ListView;)V",
)
}
}
// Force YT to add the 'advanced' quality menu for Shorts.
VideoQualityMenuOptionsFingerprint.resultOrThrow().let {
val result = it.scanResult.patternScanResult!!
val startIndex = result.startIndex
val endIndex = result.endIndex
val scanResult = it.scanResult.patternScanResult!!
val startIndex = scanResult.startIndex
if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
val insertIndex = scanResult.endIndex
it.mutableMethod.apply {
val freeRegister = getInstruction<OneRegisterInstruction>(startIndex).registerA
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
// A condition controls whether to show the three or four items quality menu.
// Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructionsWithLabels(
startIndex + 1,
addInstructions(
insertIndex,
"""
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation()Z
move-result v$freeRegister
if-nez v$freeRegister, :includeAdvancedMenu
invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$register
""",
ExternalLabel("includeAdvancedMenu", getInstruction(endIndex))
)
}
}
@@ -115,4 +119,4 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
// endregion
}
}
}

View File

@@ -10,13 +10,11 @@ internal object VideoQualityMenuOptionsFingerprint : LiteralValueFingerprint(
parameters = listOf("Landroid/content/Context", "L", "L"),
returnType = "[L",
opcodes = listOf(
Opcode.IF_EQZ, // Check if advanced menu should be shown.
Opcode.NEW_ARRAY,
Opcode.APUT_OBJECT,
Opcode.APUT_OBJECT,
Opcode.APUT_OBJECT,
Opcode.RETURN_OBJECT,
Opcode.CONST_4 // Advanced menu code path.
Opcode.CONST_4, // First instruction of method.
Opcode.CONST_4,
Opcode.IF_EQZ,
Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.IF_NEZ
),
literalSupplier = { RestoreOldVideoQualityMenuResourcePatch.videoQualityQuickMenuAdvancedMenuDescription }
)

View File

@@ -143,8 +143,41 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
* @param predicate The predicate to match.
* @return The index of the first [Instruction] that matches the predicate.
*/
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) =
this.implementation!!.instructions.indexOfFirst(predicate)
// TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
*
* @param startIndex Optional starting index to start searching from.
* @return -1 if the instruction is not found.
* @see indexOfFirstInstructionOrThrow
*/
fun Method.indexOfFirstInstruction(startIndex: Int = 0, predicate: Instruction.() -> Boolean): Int {
val index = this.implementation!!.instructions.drop(startIndex).indexOfFirst(predicate)
return if (index >= 0) {
startIndex + index
} else {
-1
}
}
/**
* Get the index of the first [Instruction] that matches the predicate, starting from [startIndex].
*
* @return the index of the instruction
* @throws PatchException
* @see indexOfFirstInstruction
*/
fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instruction.() -> Boolean): Int {
val index = indexOfFirstInstruction(startIndex, predicate)
if (index < 0) {
throw PatchException("Could not find instruction index")
}
return index
}
/**
* Return the resolved methods of [MethodFingerprint]s early.

View File

@@ -1096,8 +1096,8 @@
<string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
<string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
<string name="revanced_spoof_client_use_ios_summary_on">Client is currently spoofed to iOS\n\nSide effects include:\n• No HDR video\n• Speed menu is missing\n• Watch history may not work\n• Live streams cannot play as audio only\n• Live streams not available on older devices</string>
<string name="revanced_spoof_client_use_ios_summary_off">Client is currently spoofed to Android VR\n\nSide effects include:\n• No HDR video\n• Swipe to enter/exit fullscreen does not work\n• Kids videos do not playback\n• Paused videos can randomly resume</string>
<string name="revanced_spoof_client_use_ios_summary_on">Client is currently spoofed to iOS\n\nSide effects include:\n• No HDR video\n• Watch history may not work\n• Live streams cannot play as audio only\n• Live streams not available on older devices</string>
<string name="revanced_spoof_client_use_ios_summary_off">Client is currently spoofed to Android VR\n\nSide effects include:\n• No HDR video\n• Kids videos do not playback\n• Paused videos can randomly resume</string>
<string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
<string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
</patch>