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) # [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 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 final class app/revanced/patches/messenger/inbox/HideInboxAdsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/ads/inbox/patch/HideInboxAdsPatch; public static final field INSTANCE Lapp/revanced/patches/messenger/inbox/HideInboxAdsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)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 final class app/revanced/patches/messenger/inbox/HideInboxSubtabsPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inputfield/patch/DisableSwitchingEmojiToStickerPatch; public static final field INSTANCE Lapp/revanced/patches/messenger/inbox/HideInboxSubtabsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)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 final class app/revanced/patches/messenger/inputfield/DisableSwitchingEmojiToStickerPatch : app/revanced/patcher/patch/BytecodePatch {
public static final field INSTANCE Lapp/revanced/patches/messenger/inputfield/patch/DisableTypingIndicatorPatch; 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 fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)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 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 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 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 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 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 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 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.parallel = true
org.gradle.caching = true org.gradle.caching = true
kotlin.code.style = official 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.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch 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( @Patch(
name = "Hide inbox ads", name = "Hide inbox ads",
description = "Hides ads in inbox.", description = "Hides ads in inbox.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")] compatiblePackages = [CompatiblePackage("com.facebook.orca")],
) )
@Suppress("unused") @Suppress("unused")
object HideInboxAdsPatch : BytecodePatch( object HideInboxAdsPatch : BytecodePatch(
setOf(LoadInboxAdsFingerprint) setOf(LoadInboxAdsFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
LoadInboxAdsFingerprint.result?.mutableMethod?.apply { LoadInboxAdsFingerprint.result?.mutableMethod?.apply {
@@ -23,4 +23,3 @@ object HideInboxAdsPatch : BytecodePatch(
} ?: throw LoadInboxAdsFingerprint.exception } ?: 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.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
@@ -8,11 +8,10 @@ internal object LoadInboxAdsFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
strings = listOf( strings = listOf(
"ads_load_begin", "ads_load_begin",
"inbox_ads_fetch_start" "inbox_ads_fetch_start",
), ),
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;" 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.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction 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.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.messenger.inputfield.fingerprints.SwitchMessangeInputEmojiButtonFingerprint import app.revanced.patches.messenger.inputfield.fingerprints.SwitchMessangeInputEmojiButtonFingerprint
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch( @Patch(
name = "Disable switching emoji to sticker", name = "Disable switching emoji to sticker",
description = "Disables switching from emoji to sticker search mode in message input field.", 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") @Suppress("unused")
object DisableSwitchingEmojiToStickerPatch : BytecodePatch( object DisableSwitchingEmojiToStickerPatch : BytecodePatch(
setOf(SwitchMessangeInputEmojiButtonFingerprint) setOf(SwitchMessangeInputEmojiButtonFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SwitchMessangeInputEmojiButtonFingerprint.result?.let { SwitchMessangeInputEmojiButtonFingerprint.result?.let {
@@ -28,7 +28,7 @@ object DisableSwitchingEmojiToStickerPatch : BytecodePatch(
replaceInstruction( replaceInstruction(
setStringIndex, setStringIndex,
"const-string v$targetRegister, \"expression\"" "const-string v$targetRegister, \"expression\"",
) )
} }
} ?: throw SwitchMessangeInputEmojiButtonFingerprint.exception } ?: 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.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.messenger.inputfield.fingerprints.SendTypingIndicatorFingerprint import app.revanced.patches.messenger.inputfield.fingerprints.SendTypingIndicatorFingerprint
import app.revanced.util.exception
@Patch( @Patch(
name = "Disable typing indicator", name = "Disable typing indicator",
description = "Disables the indicator while typing a message.", description = "Disables the indicator while typing a message.",
compatiblePackages = [CompatiblePackage("com.facebook.orca")] compatiblePackages = [CompatiblePackage("com.facebook.orca")],
) )
@Suppress("unused") @Suppress("unused")
object DisableTypingIndicatorPatch : BytecodePatch( object DisableTypingIndicatorPatch : BytecodePatch(
setOf(SendTypingIndicatorFingerprint) setOf(SendTypingIndicatorFingerprint),
){ ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
SendTypingIndicatorFingerprint.result?.mutableMethod?.replaceInstruction(0, "return-void") SendTypingIndicatorFingerprint.result?.mutableMethod?.replaceInstruction(0, "return-void")
?: throw SendTypingIndicatorFingerprint.exception ?: throw SendTypingIndicatorFingerprint.exception

View File

@@ -11,7 +11,18 @@ import app.revanced.util.exception
@Patch( @Patch(
name = "Hide music video ads", 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") @Suppress("unused")
object HideMusicVideoAds : BytecodePatch( object HideMusicVideoAds : BytecodePatch(

View File

@@ -11,7 +11,18 @@ import com.android.tools.smali.dexlib2.Opcode
@Patch( @Patch(
description = "Adds more audio codec options. The new audio codecs usually result in better audio quality.", 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.") @Deprecated("This patch is no longer needed as the feature is now enabled by default.")
object CodecsUnlockPatch : BytecodePatch( object CodecsUnlockPatch : BytecodePatch(

View File

@@ -11,7 +11,18 @@ import app.revanced.util.exception
@Patch( @Patch(
name = "Enable exclusive audio playback", name = "Enable exclusive audio playback",
description = "Enables the option to play audio without video.", 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") @Suppress("unused")
object EnableExclusiveAudioPlayback : BytecodePatch( object EnableExclusiveAudioPlayback : BytecodePatch(

View File

@@ -13,7 +13,18 @@ import app.revanced.patches.music.interaction.permanentrepeat.fingerprints.Repea
@Patch( @Patch(
name = "Permanent repeat", name = "Permanent repeat",
description = "Permanently remember your repeating preference even if the playlist ends or another track is played.", 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 use = false
) )
@Suppress("unused") @Suppress("unused")
@@ -23,7 +34,7 @@ object PermanentRepeatPatch : BytecodePatch(
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
RepeatTrackFingerprint.result?.let { RepeatTrackFingerprint.result?.let {
val startIndex = it.scanResult.patternScanResult!!.endIndex val startIndex = it.scanResult.patternScanResult!!.endIndex
val repeatIndex = startIndex + 3 val repeatIndex = startIndex + 1
it.mutableMethod.apply { it.mutableMethod.apply {
addInstructionsWithLabels( addInstructionsWithLabels(

View File

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

View File

@@ -12,7 +12,18 @@ import app.revanced.util.exception
name = "Permanent shuffle", name = "Permanent shuffle",
description = "Permanently remember your shuffle preference " + description = "Permanently remember your shuffle preference " +
"even if the playlist ends or another track is played.", "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, use = false,
) )
@Suppress("unused") @Suppress("unused")

View File

@@ -13,7 +13,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@Patch( @Patch(
name = "Hide category bar", name = "Hide category bar",
description = "Hides the category bar at the top of the homepage.", 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, use = false,
) )
@Suppress("unused") @Suppress("unused")

View File

@@ -13,7 +13,18 @@ import app.revanced.util.exception
@Patch( @Patch(
name = "Minimized playback", name = "Minimized playback",
description = "Unlocks options for picture-in-picture and background 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") @Suppress("unused")
object MinimizedPlaybackPatch : BytecodePatch( object MinimizedPlaybackPatch : BytecodePatch(

View File

@@ -16,7 +16,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch( @Patch(
name = "Hide 'Get Music Premium' label", name = "Hide 'Get Music Premium' label",
description = "Hides the \"Get Music Premium\" label from the account menu and settings.", 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") @Suppress("unused")
object HideGetPremiumPatch : BytecodePatch( object HideGetPremiumPatch : BytecodePatch(

View File

@@ -22,7 +22,18 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
@Patch( @Patch(
name = "Remove upgrade button", name = "Remove upgrade button",
description = "Removes the upgrade tab from the pivot bar.", 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") @Suppress("unused")
object RemoveUpgradeButtonPatch : BytecodePatch( object RemoveUpgradeButtonPatch : BytecodePatch(

View File

@@ -12,7 +12,18 @@ import app.revanced.patches.music.misc.androidauto.fingerprints.CheckCertificate
@Patch( @Patch(
name = "Bypass certificate checks", name = "Bypass certificate checks",
description = "Bypasses certificate checks which prevent YouTube Music from working on Android Auto.", 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") @Suppress("unused")
object BypassCertificateChecksPatch : BytecodePatch(setOf(CheckCertificateFingerprint)) { object BypassCertificateChecksPatch : BytecodePatch(setOf(CheckCertificateFingerprint)) {

View File

@@ -23,7 +23,18 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
mainActivityOnCreateFingerprint = MusicActivityOnCreateFingerprint, mainActivityOnCreateFingerprint = MusicActivityOnCreateFingerprint,
integrationsPatchDependency = IntegrationsPatch::class, integrationsPatchDependency = IntegrationsPatch::class,
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch, 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( fingerprints = setOf(
ServiceCheckFingerprint, ServiceCheckFingerprint,
GooglePlayUtilityFingerprint, 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.BuildAuthorizationStringFingerprint
import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint
import app.revanced.util.getReference 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.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.iface.reference.StringReference
@Suppress("unused") @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. // 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. // Replace old.reddit.com with ssl.reddit.com to fix this.
BuildAuthorizationStringFingerprint.result!!.mutableMethod.apply { BuildAuthorizationStringFingerprint.result!!.mutableMethod.apply {
val index = indexOfFirstInstruction { val index = indexOfFirstInstructionOrThrow {
getReference<StringReference>()?.contains("old.reddit.com") == true 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.OnClearDisplayEventFingerprint
import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnRenderFirstFrameFingerprint import app.revanced.patches.tiktok.interaction.cleardisplay.fingerprints.OnRenderFirstFrameFingerprint
import app.revanced.util.exception 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.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c
@@ -34,7 +34,7 @@ object RememberClearDisplayPatch : BytecodePatch(
OnClearDisplayEventFingerprint.result?.mutableMethod?.let { OnClearDisplayEventFingerprint.result?.mutableMethod?.let {
// region Hook the "Clear display" configuration save event to remember the state of clear display. // 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 val isEnabledRegister = it.getInstruction<Instruction22c>(isEnabledIndex - 1).registerA
it.addInstructions( 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.SettingsPatch
import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint
import app.revanced.util.exception 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.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -81,16 +81,16 @@ object DownloadsPatch : BytecodePatch(
}, },
// Change the download path patch. // Change the download path patch.
DownloadPathParentFingerprint to { DownloadPathParentFingerprint to {
val targetIndex = indexOfFirstInstruction { opcode == Opcode.INVOKE_STATIC } val targetIndex = indexOfFirstInstructionOrThrow { opcode == Opcode.INVOKE_STATIC }
val downloadUriMethod = context val downloadUriMethod = context
.toMethodWalker(this) .toMethodWalker(this)
.nextMethod(targetIndex, true) .nextMethod(targetIndex, true)
.getMethod() as MutableMethod .getMethod() as MutableMethod
val firstIndex = downloadUriMethod.indexOfFirstInstruction { val firstIndex = downloadUriMethod.indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_DIRECT && ((this as Instruction35c).reference as MethodReference).name == "<init>" 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( opcode == Opcode.INVOKE_STATIC && ((this as Instruction35c).reference as MethodReference).returnType.contains(
"Uri" "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.exception
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction 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.instruction.formats.Instruction11x
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@@ -38,7 +39,7 @@ object PlaybackSpeedPatch : BytecodePatch(
SetSpeedFingerprint.result?.let { onVideoSwiped -> SetSpeedFingerprint.result?.let { onVideoSwiped ->
// Remember the playback speed of the current video. // Remember the playback speed of the current video.
GetSpeedFingerprint.result?.mutableMethod?.apply { 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 val register = getInstruction<Instruction11x>(injectIndex - 1).registerA
addInstruction( addInstruction(

View File

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

View File

@@ -42,7 +42,12 @@ import app.revanced.util.exception
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.shared.fingerprints.LayoutConstructorFingerprint 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 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.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Patch( @Patch(
@@ -52,6 +53,11 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "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( object HideAutoplayButtonPatch : BytecodePatch(
setOf(LayoutConstructorFingerprint), setOf(LayoutConstructorFingerprint),
) { ) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;"
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class) AddResourcesPatch(this::class)
@@ -67,33 +77,27 @@ object HideAutoplayButtonPatch : BytecodePatch(
SwitchPreference("revanced_hide_autoplay_button"), SwitchPreference("revanced_hide_autoplay_button"),
) )
LayoutConstructorFingerprint.result?.mutableMethod?.apply { LayoutConstructorFingerprint.resultOrThrow().mutableMethod.apply {
val layoutGenMethodInstructions = implementation!!.instructions val constIndex = indexOfIdResourceOrThrow("autonav_toggle")
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
// resolve the offsets of where to insert the branch instructions and ... // Add a conditional branch around the code that inflates and adds the auto repeat button.
val insertIndex = indexOfIdResourceOrThrow("autonav_preview_stub") val gotoIndex = indexOfFirstInstructionOrThrow(constIndex) {
val parameterTypes = getReference<MethodReference>()?.parameterTypes
// where to branch away opcode == Opcode.INVOKE_VIRTUAL &&
val branchIndex = parameterTypes?.size == 2 &&
layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1) parameterTypes.first() == "Landroid/view/ViewStub;"
.indexOfFirst { } + 1
((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
addInstructionsWithLabels( addInstructionsWithLabels(
insertIndex, constIndex,
""" """
invoke-static {}, Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;->isButtonShown()Z invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->hideAutoPlayButton()Z
move-result v$clobberRegister move-result v$constRegister
if-eqz v$clobberRegister, :hidden 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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference 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.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference 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.09.38",
"19.10.39", "19.10.39",
"19.11.43", "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. // Hide navigation button labels.
CreatePivotBarFingerprint.result?.mutableMethod?.apply { CreatePivotBarFingerprint.result?.mutableMethod?.apply {
val setTextIndex = indexOfFirstInstruction { val setTextIndex = indexOfFirstInstructionOrThrow {
getReference<MethodReference>()?.name == "setText" getReference<MethodReference>()?.name == "setText"
} }

View File

@@ -46,7 +46,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode 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.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction 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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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 // region Mix playlists
ParseElementFromBufferFingerprint.resultOrThrow().let { result -> ParseElementFromBufferFingerprint.resultOrThrow().let { result ->
val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex val startIndex = result.scanResult.patternScanResult!!.startIndex
result.mutableMethod.apply { result.mutableMethod.apply {
val conversionContextRegister = val freeRegister = "v0"
getInstruction<TwoRegisterInstruction>(consumeByteBufferIndex - 2).registerA val byteArrayParameter = "p3"
val byteBufferRegister = getInstruction<FiveRegisterInstruction>(consumeByteBufferIndex).registerD val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC } val returnEmptyComponentInstruction = getInstructions().last { it.opcode == Opcode.INVOKE_STATIC }
addInstructionsWithLabels( addInstructionsWithLabels(
consumeByteBufferIndex, startIndex + 1,
""" """
invoke-static {v$conversionContextRegister, v$byteBufferRegister}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v0 # Conveniently same register happens to be free. move-result $freeRegister
if-nez v0, :return_empty_component if-nez $freeRegister, :return_empty_component
const/4 $freeRegister, 0x0 # Restore register, required for 19.16
""", """,
ExternalLabel("return_empty_component", returnEmptyComponentInstruction), ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
) )

View File

@@ -4,7 +4,11 @@ import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object ParseElementFromBufferFingerprint : MethodFingerprint( internal object ParseElementFromBufferFingerprint : MethodFingerprint(
parameters = listOf("L","L","[B", "L","L"), parameters = listOf("L", "L", "[B", "L", "L"),
opcodes = listOf(Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT), opcodes = listOf(
strings = listOf("Failed to parse Element") 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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.09.38",
"19.10.39", "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

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

View File

@@ -41,7 +41,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.BytecodePatch 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.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.all.misc.resources.AddResourcesPatch 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.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception import app.revanced.util.exception
import app.revanced.util.getReference 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.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction 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.OneRegisterInstruction
@@ -46,7 +45,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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 { UserWasInShortsFingerprint.result?.mutableMethod?.apply {
val listenableInstructionIndex = indexOfFirstInstruction { val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_INTERFACE && opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" && getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
getReference<MethodReference>()?.name == "isDone" getReference<MethodReference>()?.name == "isDone"
} }
if (listenableInstructionIndex < 0) throw PatchException("Could not find instruction index")
val originalInstructionRegister = getInstruction<FiveRegisterInstruction>(listenableInstructionIndex).registerC val originalInstructionRegister = getInstruction<FiveRegisterInstruction>(listenableInstructionIndex).registerC
val freeRegister = getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA 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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.PatchException
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch 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.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.all.misc.resources.AddResourcesPatch 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
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference 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.*
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.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
@@ -63,17 +60,29 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
"19.09.38", "19.09.38",
"19.10.39", "19.10.39",
"19.11.43", "19.11.43",
"19.12.41",
"19.13.37",
"19.14.43",
"19.15.36",
"19.16.39",
], ],
), ),
], ],
) )
object SpoofClientPatch : BytecodePatch( object SpoofClientPatch : BytecodePatch(
setOf( setOf(
// Client type spoof.
BuildInitPlaybackRequestFingerprint, BuildInitPlaybackRequestFingerprint,
BuildPlayerRequestURIFingerprint, BuildPlayerRequestURIFingerprint,
SetPlayerRequestClientTypeFingerprint, SetPlayerRequestClientTypeFingerprint,
CreatePlayerRequestBodyFingerprint, CreatePlayerRequestBodyFingerprint,
CreatePlayerRequestBodyWithModelFingerprint, CreatePlayerRequestBodyWithModelFingerprint,
// Player gesture config.
PlayerGestureConfigSyntheticFingerprint,
// Player speed menu item.
CreatePlaybackSpeedMenuItemFingerprint,
), ),
) { ) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = private const val INTEGRATIONS_CLASS_DESCRIPTOR =
@@ -87,7 +96,7 @@ object SpoofClientPatch : BytecodePatch(
SettingsPatch.PreferenceScreen.MISC.addPreferences( SettingsPatch.PreferenceScreen.MISC.addPreferences(
PreferenceScreen( PreferenceScreen(
key = "revanced_spoof_client_screen", key = "revanced_spoof_client_screen",
sorting = Sorting.UNSORTED, sorting = PreferenceScreen.Sorting.UNSORTED,
preferences = setOf( preferences = setOf(
SwitchPreference("revanced_spoof_client"), SwitchPreference("revanced_spoof_client"),
SwitchPreference("revanced_spoof_client_use_ios"), SwitchPreference("revanced_spoof_client_use_ios"),
@@ -162,15 +171,14 @@ object SpoofClientPatch : BytecodePatch(
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let { val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method) 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. // The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
instructions.subList( val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getClientModelIndex) {
getClientModelIndex, opcode == Opcode.IPUT_OBJECT
instructions.size, }
).find { instruction ->
instruction.opcode == Opcode.IPUT_OBJECT it.mutableMethod.getInstruction(index).getReference<FieldReference>()
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientModelField") ?: throw PatchException("Could not find clientInfoClientModelField")
} }
// endregion // endregion
@@ -243,5 +251,56 @@ object SpoofClientPatch : BytecodePatch(
// endregion // 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.09.38",
"19.10.39", "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

@@ -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.ABUriParserFingerprint
import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint
import app.revanced.patches.youtube.misc.settings.SettingsPatch 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 import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch( @Patch(
@@ -38,27 +38,32 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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") @Suppress("unused")
object BypassURLRedirectsPatch : BytecodePatch( object BypassURLRedirectsPatch : BytecodePatch(
setOf(ABUriParserFingerprint, HTTPUriParserFingerprint) setOf(ABUriParserFingerprint, HTTPUriParserFingerprint),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class) AddResourcesPatch(this::class)
SettingsPatch.PreferenceScreen.MISC.addPreferences( SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference("revanced_bypass_url_redirects") SwitchPreference("revanced_bypass_url_redirects"),
) )
mapOf( mapOf(
ABUriParserFingerprint to 7, // Offset to Uri.parse. ABUriParserFingerprint to 7, // Offset to Uri.parse.
HTTPUriParserFingerprint to 0 // Offset to Uri.parse. HTTPUriParserFingerprint to 0, // Offset to Uri.parse.
).map { (fingerprint, offset) -> ).map { (fingerprint, offset) ->
(fingerprint.result ?: throw fingerprint.exception) to offset fingerprint.resultOrThrow() to offset
}.forEach { (result, offset) -> }.forEach { (result, offset) ->
result.mutableMethod.apply { result.mutableMethod.apply {
val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset
@@ -67,11 +72,11 @@ object BypassURLRedirectsPatch : BytecodePatch(
replaceInstruction( replaceInstruction(
insertIndex, insertIndex,
"invoke-static {v$uriStringRegister}," + "invoke-static {v$uriStringRegister}," +
"Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" + "Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" +
"->" + "->" +
"parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;" "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT, Opcode.RETURN_OBJECT,
Opcode.CHECK_CAST Opcode.CHECK_CAST,
), ),
customFingerprint = { methodDef, classDef -> customFingerprint = custom@{ methodDef, classDef ->
// This method is always called "a" because this kind of class always has a single method. // This method is always called "a" because this kind of class always has a single (non synthetic) method.
methodDef.name == "a" && classDef.methods.count() == 3
} 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.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.* import app.revanced.patches.youtube.misc.litho.filter.fingerprints.*
import app.revanced.util.getReference 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.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction 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.Instruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction 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.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import java.io.Closeable import java.io.Closeable
@Patch( @Patch(
@@ -108,11 +106,10 @@ object LithoFilterPatch : BytecodePatch(
val emptyComponentFieldIndex = builderMethodIndex + 2 val emptyComponentFieldIndex = builderMethodIndex + 2
bytesToComponentContextMethod.mutableMethod.apply { bytesToComponentContextMethod.mutableMethod.apply {
val insertHookIndex = indexOfFirstInstruction { val insertHookIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT && opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;" getReference<FieldReference>()?.type == "Ljava/lang/StringBuilder;"
} + 1 } + 1
if (insertHookIndex <= 0) throw PatchException("Could not find insert index")
// region Get free registers that this patch uses. // region Get free registers that this patch uses.
// Registers are overwritten right after they are used in this patch, therefore free to clobber. // 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.KidsMinimizedPlaybackPolicyControllerFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint 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.MinimizedPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsParentFingerprint
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.patches.youtube.video.information.VideoInformationPatch
@@ -25,6 +24,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
name = "Minimized playback", name = "Minimized playback",
description = "Unlocks options for picture-in-picture and background playback.", description = "Unlocks options for picture-in-picture and background playback.",
dependencies = [ dependencies = [
MinimizedPlaybackResourcePatch::class,
IntegrationsPatch::class, IntegrationsPatch::class,
PlayerTypeHookPatch::class, PlayerTypeHookPatch::class,
VideoInformationPatch::class, VideoInformationPatch::class,
@@ -47,7 +47,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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( object MinimizedPlaybackPatch : BytecodePatch(
setOf( setOf(
MinimizedPlaybackManagerFingerprint, MinimizedPlaybackManagerFingerprint,
MinimizedPlaybackSettingsParentFingerprint, MinimizedPlaybackSettingsFingerprint,
KidsMinimizedPlaybackPolicyControllerFingerprint KidsMinimizedPlaybackPolicyControllerFingerprint
) )
) { ) {
@@ -82,11 +87,6 @@ object MinimizedPlaybackPatch : BytecodePatch(
} ?: throw MinimizedPlaybackManagerFingerprint.exception } ?: throw MinimizedPlaybackManagerFingerprint.exception
// Enable minimized playback option in YouTube settings // Enable minimized playback option in YouTube settings
MinimizedPlaybackSettingsParentFingerprint.result ?: throw MinimizedPlaybackSettingsParentFingerprint.exception
MinimizedPlaybackSettingsFingerprint.resolve(
context,
MinimizedPlaybackSettingsParentFingerprint.result!!.classDef
)
MinimizedPlaybackSettingsFingerprint.result?.apply { MinimizedPlaybackSettingsFingerprint.result?.apply {
val booleanCalls = method.implementation!!.instructions.withIndex() val booleanCalls = method.implementation!!.instructions.withIndex()
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" } .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 package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.extensions.or 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.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
internal object MinimizedPlaybackSettingsFingerprint : MethodFingerprint( internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
returnType = "Ljava/lang/String;", returnType = "Ljava/lang/String;",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(), parameters = listOf(),
@@ -16,8 +17,7 @@ internal object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.IF_NEZ, Opcode.IF_NEZ,
Opcode.GOTO, Opcode.GOTO
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST
), ),
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.navigation.fingerprints.*
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.resultOrThrow import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction 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, // Insert before the first ViewGroup method call after inflating,
// so this works regardless which layout is used. // so this works regardless which layout is used.
ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply { ActionBarSearchResultsFingerprint.resultOrThrow().mutableMethod.apply {
val instructionIndex = indexOfFirstInstruction { val instructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_VIRTUAL && getReference<MethodReference>()?.name == "setLayoutDirection" 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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction 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.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch 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.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch 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.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch
import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch
@@ -23,7 +23,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
IntegrationsPatch::class, IntegrationsPatch::class,
RestoreOldVideoQualityMenuResourcePatch::class, RestoreOldVideoQualityMenuResourcePatch::class,
LithoFilterPatch::class, LithoFilterPatch::class,
RecyclerViewTreeHookPatch::class RecyclerViewTreeHookPatch::class,
], ],
compatiblePackages = [ compatiblePackages = [
CompatiblePackage( CompatiblePackage(
@@ -47,20 +47,25 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
"19.08.36", "19.08.36",
"19.09.38", "19.09.38",
"19.10.39", "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") @Suppress("unused")
object RestoreOldVideoQualityMenuPatch : BytecodePatch( object RestoreOldVideoQualityMenuPatch : BytecodePatch(
setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint) setOf(VideoQualityMenuViewInflateFingerprint, VideoQualityMenuOptionsFingerprint),
) { ) {
private const val FILTER_CLASS_DESCRIPTOR = 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 = 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) { override fun execute(context: BytecodeContext) {
// region Patch for the old type of the video quality menu. // region Patch for the old type of the video quality menu.
@@ -75,31 +80,30 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
addInstruction( addInstruction(
checkCastIndex + 1, checkCastIndex + 1,
"invoke-static { v$listViewRegister }, " + "invoke-static { v$listViewRegister }, " +
"$INTEGRATIONS_CLASS_DESCRIPTOR->" + "$INTEGRATIONS_CLASS_DESCRIPTOR->" +
"showOldVideoQualityMenu(Landroid/widget/ListView;)V" "showOldVideoQualityMenu(Landroid/widget/ListView;)V",
) )
} }
} }
// Force YT to add the 'advanced' quality menu for Shorts. // Force YT to add the 'advanced' quality menu for Shorts.
VideoQualityMenuOptionsFingerprint.resultOrThrow().let { VideoQualityMenuOptionsFingerprint.resultOrThrow().let {
val result = it.scanResult.patternScanResult!! val scanResult = it.scanResult.patternScanResult!!
val startIndex = result.startIndex val startIndex = scanResult.startIndex
val endIndex = result.endIndex if (startIndex != 0) throw PatchException("Unexpected opcode start index: $startIndex")
val insertIndex = scanResult.endIndex
it.mutableMethod.apply { 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. // 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. // Force the four items quality menu to make the "Advanced" item visible, necessary for the patch.
addInstructionsWithLabels( addInstructions(
startIndex + 1, insertIndex,
""" """
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation()Z invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->forceAdvancedVideoQualityMenuCreation(Z)Z
move-result v$freeRegister move-result v$register
if-nez v$freeRegister, :includeAdvancedMenu
""", """,
ExternalLabel("includeAdvancedMenu", getInstruction(endIndex))
) )
} }
} }
@@ -115,4 +119,4 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch(
// endregion // endregion
} }
} }

View File

@@ -10,13 +10,11 @@ internal object VideoQualityMenuOptionsFingerprint : LiteralValueFingerprint(
parameters = listOf("Landroid/content/Context", "L", "L"), parameters = listOf("Landroid/content/Context", "L", "L"),
returnType = "[L", returnType = "[L",
opcodes = listOf( opcodes = listOf(
Opcode.IF_EQZ, // Check if advanced menu should be shown. Opcode.CONST_4, // First instruction of method.
Opcode.NEW_ARRAY, Opcode.CONST_4,
Opcode.APUT_OBJECT, Opcode.IF_EQZ,
Opcode.APUT_OBJECT, Opcode.IGET_BOOLEAN, // Use the quality menu, that contains the advanced menu.
Opcode.APUT_OBJECT, Opcode.IF_NEZ
Opcode.RETURN_OBJECT,
Opcode.CONST_4 // Advanced menu code path.
), ),
literalSupplier = { RestoreOldVideoQualityMenuResourcePatch.videoQualityQuickMenuAdvancedMenuDescription } 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. * @param predicate The predicate to match.
* @return The index of the first [Instruction] that matches the predicate. * @return The index of the first [Instruction] that matches the predicate.
*/ */
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = // TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
this.implementation!!.instructions.indexOfFirst(predicate) @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. * 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_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_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_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_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• 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_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_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> <string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
</patch> </patch>