chore: Merge branch dev
to main
(#3300)
This commit is contained in:
commit
9025b6271c
71
CHANGELOG.md
71
CHANGELOG.md
|
@ -1,3 +1,74 @@
|
|||
# [4.10.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.9...v4.10.0-dev.10) (2024-06-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Correct invalid string name ([b84494f](https://github.com/ReVanced/revanced-patches/commit/b84494f4e26e040ada69ed7a516f331f2d47da87))
|
||||
|
||||
# [4.10.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.8...v4.10.0-dev.9) (2024-06-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Hide description components:** Replace `Hide game section` and `Hide music section` with `Hide attributes section` ([#3327](https://github.com/ReVanced/revanced-patches/issues/3327)) ([0198a43](https://github.com/ReVanced/revanced-patches/commit/0198a436f97b127a2a5dd283644254f9a0ae3e43))
|
||||
|
||||
# [4.10.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.7...v4.10.0-dev.8) (2024-06-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Comments:** Add `Hide 'Create a Short' button` option ([#3333](https://github.com/ReVanced/revanced-patches/issues/3333)) ([be9e244](https://github.com/ReVanced/revanced-patches/commit/be9e24420fda80903e44e2e2278ea4904ecac4e1))
|
||||
|
||||
# [4.10.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.6...v4.10.0-dev.7) (2024-06-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Change version code` patch ([#3338](https://github.com/ReVanced/revanced-patches/issues/3338)) ([685ef39](https://github.com/ReVanced/revanced-patches/commit/685ef39119daf1033a83262982519531c481c40f))
|
||||
|
||||
# [4.10.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.5...v4.10.0-dev.6) (2024-06-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Comments:** Add `Hide Thanks button` and `Hide 'Comments by members' header` options ([#3317](https://github.com/ReVanced/revanced-patches/issues/3317)) ([9c4c4f0](https://github.com/ReVanced/revanced-patches/commit/9c4c4f05a762d745404101bbc3925ab4eba2deb8))
|
||||
|
||||
# [4.10.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.4...v4.10.0-dev.5) (2024-06-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube - Client spoof:** Correctly play more livestreams using Android VR ([#3316](https://github.com/ReVanced/revanced-patches/issues/3316)) ([c05264a](https://github.com/ReVanced/revanced-patches/commit/c05264af3944cbfe8d9aa34fb0e0fddb05a1d42f))
|
||||
|
||||
# [4.10.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.3...v4.10.0-dev.4) (2024-06-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Boost for Reddit:** Add `Fix audio missing in video downloads` patch ([#3287](https://github.com/ReVanced/revanced-patches/issues/3287)) ([a9258d4](https://github.com/ReVanced/revanced-patches/commit/a9258d48d3ddf8552ab56219677a3b31ee553666))
|
||||
|
||||
# [4.10.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.2...v4.10.0-dev.3) (2024-06-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **Boost For Reddit:** Add `Fix /s/ links` patch ([#3154](https://github.com/ReVanced/revanced-patches/issues/3154)) ([5fa9fd2](https://github.com/ReVanced/revanced-patches/commit/5fa9fd2dfef43838d7311a967a3e805256a5d116))
|
||||
|
||||
# [4.10.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.10.0-dev.1...v4.10.0-dev.2) (2024-06-08)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **YouTube Music:** Rename `Minimized playback` to `Remove background playback restrictions` ([#3315](https://github.com/ReVanced/revanced-patches/issues/3315)) ([3c31e55](https://github.com/ReVanced/revanced-patches/commit/3c31e55b13d9495e857f068f8cd2b4320112d763))
|
||||
* **YouTube:** Rename `Minimized playback` to `Remove background playback restrictions` ([#3314](https://github.com/ReVanced/revanced-patches/issues/3314)) ([37d415b](https://github.com/ReVanced/revanced-patches/commit/37d415b53af4771d9c97a8b1c153be32bf3ac2e0))
|
||||
|
||||
# [4.10.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.9.0...v4.10.0-dev.1) (2024-06-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **YouTube - Miniplayer:** Rename `Tablet mini player` and allow selecting the style of the in-app miniplayer ([#3302](https://github.com/ReVanced/revanced-patches/issues/3302)) ([5511736](https://github.com/ReVanced/revanced-patches/commit/5511736b0c5dd409db6a68db0f85e389bb95be47))
|
||||
|
||||
# [4.9.0](https://github.com/ReVanced/revanced-patches/compare/v4.8.3...v4.9.0) (2024-06-02)
|
||||
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ with the maintainers of ReVanced Patches. This will help you determine whether y
|
|||
and whether it is worth your time to implement it
|
||||
2. Development happens on the `dev` branch. Fork the repository and create your branch from `dev`
|
||||
3. Commit your changes. In case you are contributing a new patch, make sure to follow the conventions for patches
|
||||
described in the [documentation](https://github.com/ReVanced/revanced-patches/tree/docs/docs)
|
||||
described in the [ReVanced Patcher documentation](https://github.com/ReVanced/revanced-patcher/tree/main/docs)
|
||||
4. Submit a pull request to the `dev` branch of the repository and reference issues
|
||||
that your pull request closes in the description of your pull request
|
||||
5. Our team will review your pull request and provide feedback. Once your pull request is approved,
|
||||
|
|
|
@ -105,6 +105,12 @@ public final class app/revanced/patches/all/misc/transformation/IMethodCall$Defa
|
|||
public static fun replaceInvokeVirtualWithIntegrations (Lapp/revanced/patches/all/misc/transformation/IMethodCall;Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lcom/android/tools/smali/dexlib2/iface/instruction/formats/Instruction35c;I)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/misc/versioncode/ChangeVersionCodePatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/misc/versioncode/ChangeVersionCodePatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch;
|
||||
public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object;
|
||||
|
@ -403,6 +409,12 @@ public final class app/revanced/patches/music/misc/androidauto/BypassCertificate
|
|||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/music/misc/backgroundplayback/BackgroundPlaybackPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/misc/backgroundplayback/BackgroundPlaybackPatch;
|
||||
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/music/misc/gms/Constants {
|
||||
public static final field INSTANCE Lapp/revanced/patches/music/misc/gms/Constants;
|
||||
}
|
||||
|
@ -529,6 +541,18 @@ public final class app/revanced/patches/reddit/ad/general/HideAdsPatch : app/rev
|
|||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/reddit/customclients/BaseFixSLinksPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Ljava/util/Set;)V
|
||||
public synthetic fun <init> (Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
protected abstract fun getIntegrationsClassDescriptor ()Ljava/lang/String;
|
||||
protected final fun getResolveSLinkMethod ()Ljava/lang/String;
|
||||
protected final fun getSetAccessTokenMethod ()Ljava/lang/String;
|
||||
protected abstract fun patchNavigationHandler (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
protected abstract fun patchSetAccessToken (Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
}
|
||||
|
||||
public abstract class app/revanced/patches/reddit/customclients/BaseSpoofClientPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public fun <init> (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V
|
||||
public synthetic fun <init> (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
|
@ -564,6 +588,20 @@ public final class app/revanced/patches/reddit/customclients/boostforreddit/api/
|
|||
public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/fix/downloads/FixAudioMissingInDownloadsPatch;
|
||||
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/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch : app/revanced/patches/reddit/customclients/BaseFixSLinksPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/fix/slink/FixSLinksPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/misc/integrations/IntegrationsPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch;
|
||||
public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
|
@ -642,10 +680,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/detec
|
|||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patches/reddit/customclients/BaseFixSLinksPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch;
|
||||
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/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/misc/integrations/IntegrationsPatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
|
@ -1528,6 +1568,12 @@ public final class app/revanced/patches/youtube/layout/hide/time/HideTimestampPa
|
|||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/miniplayer/MiniplayerPatch;
|
||||
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/youtube/layout/panels/popup/PlayerPopupPanelsPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch;
|
||||
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
|
||||
|
@ -1632,6 +1678,12 @@ public final class app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch
|
|||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch : app/revanced/patcher/patch/BytecodePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/backgroundplayback/BackgroundPlaybackPatch;
|
||||
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/youtube/misc/debugging/DebuggingPatch : app/revanced/patcher/patch/ResourcePatch {
|
||||
public static final field INSTANCE Lapp/revanced/patches/youtube/misc/debugging/DebuggingPatch;
|
||||
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
|
||||
|
@ -1894,6 +1946,7 @@ public final class app/revanced/patches/yuka/misc/unlockpremium/UnlockPremiumPat
|
|||
public final class app/revanced/util/BytecodeUtilsKt {
|
||||
public static final fun containsWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)Z
|
||||
public static final fun findMutableMethodOf (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lcom/android/tools/smali/dexlib2/iface/Method;)Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;
|
||||
public static final fun findOpcodeIndicesReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)Ljava/util/List;
|
||||
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
|
||||
|
@ -1901,6 +1954,7 @@ public final class app/revanced/util/BytecodeUtilsKt {
|
|||
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 indexOfFirstWideLiteralInstructionValueOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
|
||||
public static final fun indexOfIdResource (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
public static final fun indexOfIdResourceOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/String;)I
|
||||
public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
org.gradle.parallel = true
|
||||
org.gradle.caching = true
|
||||
kotlin.code.style = official
|
||||
version = 4.9.0
|
||||
version = 4.10.0-dev.10
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package app.revanced.patches.all.misc.versioncode
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.intPatchOption
|
||||
import app.revanced.util.getNode
|
||||
import org.w3c.dom.Element
|
||||
|
||||
@Patch(
|
||||
name = "Change version code",
|
||||
description = "Changes the version code of the app. By default the highest version code is set. " +
|
||||
"This allows older versions of an app to be installed " +
|
||||
"if their version code is set to the same or a higher value and can stop app stores to update the app.",
|
||||
use = false,
|
||||
)
|
||||
@Suppress("unused")
|
||||
object ChangeVersionCodePatch : ResourcePatch() {
|
||||
private val versionCode by intPatchOption(
|
||||
key = "versionCode",
|
||||
default = Int.MAX_VALUE,
|
||||
values = mapOf(
|
||||
"Lowest" to 1,
|
||||
"Highest" to Int.MAX_VALUE,
|
||||
),
|
||||
title = "Version code",
|
||||
description = "The version code to use",
|
||||
required = true,
|
||||
) {
|
||||
it!! >= 1
|
||||
}
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
context.document["AndroidManifest.xml"].use { document ->
|
||||
val manifestElement = document.getNode("manifest") as Element
|
||||
manifestElement.setAttribute("android:versionCode", "$versionCode")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +1,13 @@
|
|||
package app.revanced.patches.music.layout.minimizedplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.BackgroundPlaybackDisableFingerprint
|
||||
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patches.music.misc.backgroundplayback.BackgroundPlaybackPatch
|
||||
|
||||
@Patch(
|
||||
name = "Minimized playback",
|
||||
description = "Unlocks options for picture-in-picture and background playback.",
|
||||
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")
|
||||
@Deprecated("This patch has been merged into BackgroundPlaybackPatch.")
|
||||
object MinimizedPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint,
|
||||
BackgroundPlaybackDisableFingerprint,
|
||||
),
|
||||
dependencies = setOf(BackgroundPlaybackPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint.result?.mutableMethod?.addInstruction(
|
||||
0,
|
||||
"return-void",
|
||||
) ?: throw KidsMinimizedPlaybackPolicyControllerFingerprint.exception
|
||||
|
||||
BackgroundPlaybackDisableFingerprint.result?.mutableMethod?.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""",
|
||||
) ?: throw BackgroundPlaybackDisableFingerprint.exception
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package app.revanced.patches.music.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.music.misc.backgroundplayback.fingerprints.BackgroundPlaybackDisableFingerprint
|
||||
import app.revanced.patches.music.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
name = "Remove background playback restrictions",
|
||||
description = "Removes restrictions on background playback.",
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.apps.youtube.music",
|
||||
[
|
||||
"6.45.54",
|
||||
"6.51.53",
|
||||
"7.01.53",
|
||||
"7.02.52",
|
||||
"7.03.52",
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object BackgroundPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint,
|
||||
BackgroundPlaybackDisableFingerprint,
|
||||
),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"return-void",
|
||||
)
|
||||
|
||||
BackgroundPlaybackDisableFingerprint.resultOrThrow().mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
const/4 v0, 0x1
|
||||
return v0
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.music.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
|
@ -1,11 +1,11 @@
|
|||
package app.revanced.patches.music.layout.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.music.misc.backgroundplayback.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 KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
internal object KidsBackgroundPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
"V",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("I", "L", "Z"),
|
|
@ -2,10 +2,11 @@ package app.revanced.patches.music.premium.backgroundplay
|
|||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patches.music.layout.minimizedplayback.MinimizedPlaybackPatch
|
||||
@Deprecated("This patch has been merged into MinimizedPlaybackPatch.")
|
||||
import app.revanced.patches.music.misc.backgroundplayback.BackgroundPlaybackPatch
|
||||
|
||||
@Deprecated("This patch has been merged into BackgroundPlaybackPatch.")
|
||||
object BackgroundPlayPatch : BytecodePatch(
|
||||
dependencies = setOf(MinimizedPlaybackPatch::class),
|
||||
dependencies = setOf(BackgroundPlaybackPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package app.revanced.patches.reddit.customclients
|
||||
|
||||
import app.revanced.patcher.PatchClass
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
abstract class BaseFixSLinksPatch(
|
||||
private val handleNavigationFingerprint: MethodFingerprint,
|
||||
private val setAccessTokenFingerprint: MethodFingerprint,
|
||||
compatiblePackages: Set<CompatiblePackage>,
|
||||
dependencies: Set<PatchClass> = emptySet(),
|
||||
) : BytecodePatch(
|
||||
name = "Fix /s/ links",
|
||||
fingerprints = setOf(handleNavigationFingerprint, setAccessTokenFingerprint),
|
||||
compatiblePackages = compatiblePackages,
|
||||
dependencies = dependencies,
|
||||
) {
|
||||
protected abstract val integrationsClassDescriptor: String
|
||||
|
||||
protected val resolveSLinkMethod =
|
||||
"patchResolveSLink(Ljava/lang/String;)Z"
|
||||
|
||||
protected val setAccessTokenMethod =
|
||||
"patchSetAccessToken(Ljava/lang/String;)V"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
handleNavigationFingerprint.resultOrThrow().patchNavigationHandler(context)
|
||||
setAccessTokenFingerprint.resultOrThrow().patchSetAccessToken(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Patch app's navigation handler to resolve /s/ links.
|
||||
*
|
||||
* @param context The current [BytecodeContext].
|
||||
*
|
||||
*/
|
||||
protected abstract fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext)
|
||||
|
||||
/**
|
||||
* Patch access token setup in app to resolve /s/ links with an access token
|
||||
* in order to bypass API bans when making unauthorized requests.
|
||||
*
|
||||
* @param context The current [BytecodeContext].
|
||||
*/
|
||||
protected abstract fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads.fingerprints.DownloadAudioFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
name = "Fix missing audio in video downloads",
|
||||
description = "Fixes audio missing in videos downloaded from v.redd.it.",
|
||||
compatiblePackages = [CompatiblePackage("com.rubenmayayo.reddit")],
|
||||
)
|
||||
@Suppress("unused")
|
||||
object FixAudioMissingInDownloadsPatch : BytecodePatch(
|
||||
setOf(DownloadAudioFingerprint),
|
||||
) {
|
||||
private val endpointReplacements = mapOf(
|
||||
"/DASH_audio.mp4" to "/DASH_AUDIO_128.mp4",
|
||||
"/audio" to "/DASH_AUDIO_64.mp4",
|
||||
)
|
||||
override fun execute(context: BytecodeContext) {
|
||||
DownloadAudioFingerprint.resultOrThrow().let { result ->
|
||||
result.scanResult.stringsScanResult!!.matches.take(2).forEach { match ->
|
||||
result.mutableMethod.apply {
|
||||
val replacement = endpointReplacements[match.string]
|
||||
val register = getInstruction<OneRegisterInstruction>(match.index).registerA
|
||||
|
||||
replaceInstruction(match.index, "const-string v$register, \"$replacement\"")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.downloads.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object DownloadAudioFingerprint : MethodFingerprint(
|
||||
strings = setOf("/DASH_audio.mp4", "/audio", "v.redd.it", "/"),
|
||||
)
|
|
@ -0,0 +1,44 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.reddit.customclients.BaseFixSLinksPatch
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints.GetOAuthAccessTokenFingerprint
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints.HandleNavigationFingerprint
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.IntegrationsPatch
|
||||
|
||||
@Suppress("unused")
|
||||
object FixSLinksPatch : BaseFixSLinksPatch(
|
||||
handleNavigationFingerprint = HandleNavigationFingerprint,
|
||||
setAccessTokenFingerprint = GetOAuthAccessTokenFingerprint,
|
||||
compatiblePackages = setOf(CompatiblePackage("com.rubenmayayo.reddit")),
|
||||
dependencies = setOf(IntegrationsPatch::class),
|
||||
) {
|
||||
override val integrationsClassDescriptor = "Lapp/revanced/integrations/boostforreddit/FixSLinksPatch;"
|
||||
|
||||
override fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) {
|
||||
mutableMethod.apply {
|
||||
val urlRegister = "p1"
|
||||
val tempRegister = "v1"
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { $urlRegister }, $integrationsClassDescriptor->$resolveSLinkMethod
|
||||
move-result $tempRegister
|
||||
if-eqz $tempRegister, :continue
|
||||
return $tempRegister
|
||||
""",
|
||||
ExternalLabel("continue", getInstruction(0)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) = mutableMethod.addInstruction(
|
||||
3,
|
||||
"invoke-static { v0 }, $integrationsClassDescriptor->$setAccessTokenMethod",
|
||||
)
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object GetOAuthAccessTokenFingerprint : MethodFingerprint(
|
||||
strings = listOf("access_token"),
|
||||
accessFlags = AccessFlags.PUBLIC.value,
|
||||
returnType = "Ljava/lang/String",
|
||||
customFingerprint = { _, classDef -> classDef.type == "Lnet/dean/jraw/http/oauth/OAuthData;" },
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.fingerprints
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object HandleNavigationFingerprint : MethodFingerprint(
|
||||
strings = listOf(
|
||||
"android.intent.action.SEARCH",
|
||||
"subscription",
|
||||
"sort",
|
||||
"period",
|
||||
"boostforreddit.com/themes",
|
||||
),
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
import app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.fingerprints.InitFingerprint
|
||||
|
||||
@Patch(requiresIntegrations = true)
|
||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||
setOf(InitFingerprint)
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package app.revanced.patches.reddit.customclients.boostforreddit.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object InitFingerprint : IntegrationsFingerprint(
|
||||
customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/rubenmayayo/reddit/MyApplication;" && methodDef.name == "onCreate" },
|
||||
insertIndexResolver = { 1 } // Insert after call to super class.
|
||||
)
|
|
@ -1,32 +1,49 @@
|
|||
package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprintResult
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.reddit.customclients.BaseFixSLinksPatch
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.LinkHelperOpenLinkFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.SetAuthorizationHeaderFingerprint
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.IntegrationsPatch
|
||||
|
||||
@Patch(
|
||||
name = "Fix /s/ links",
|
||||
description = "Fixes the issue where /s/ links do not work.",
|
||||
compatiblePackages = [
|
||||
@Suppress("unused")
|
||||
object FixSLinksPatch : BaseFixSLinksPatch(
|
||||
handleNavigationFingerprint = LinkHelperOpenLinkFingerprint,
|
||||
setAccessTokenFingerprint = SetAuthorizationHeaderFingerprint,
|
||||
compatiblePackages = setOf(
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync"),
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync.pro"),
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync.dev")
|
||||
],
|
||||
requiresIntegrations = true
|
||||
)
|
||||
object FixSLinksPatch : BytecodePatch(
|
||||
setOf(LinkHelperOpenLinkFingerprint)
|
||||
CompatiblePackage("com.laurencedawson.reddit_sync.dev"),
|
||||
),
|
||||
dependencies = setOf(IntegrationsPatch::class),
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) =
|
||||
LinkHelperOpenLinkFingerprint.result?.mutableMethod?.addInstructions(
|
||||
1,
|
||||
"""
|
||||
invoke-static { p3 }, Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;->resolveSLink(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object p3
|
||||
"""
|
||||
) ?: throw LinkHelperOpenLinkFingerprint.exception
|
||||
override val integrationsClassDescriptor = "Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;"
|
||||
|
||||
override fun MethodFingerprintResult.patchNavigationHandler(context: BytecodeContext) {
|
||||
mutableMethod.apply {
|
||||
val urlRegister = "p3"
|
||||
val tempRegister = "v2"
|
||||
|
||||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { $urlRegister }, $integrationsClassDescriptor->$resolveSLinkMethod
|
||||
move-result $tempRegister
|
||||
if-eqz $tempRegister, :continue
|
||||
return $tempRegister
|
||||
""",
|
||||
ExternalLabel("continue", getInstruction(0)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun MethodFingerprintResult.patchSetAccessToken(context: BytecodeContext) = mutableMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static { p0 }, $integrationsClassDescriptor->$setAccessTokenMethod",
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object SetAuthorizationHeaderFingerprint : MethodFingerprint(
|
||||
strings = listOf("Authorization", "bearer "),
|
||||
returnType = "Ljava/util/HashMap;",
|
||||
customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/laurencedawson/reddit_sync/singleton/a;" },
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations
|
||||
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch
|
||||
import app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.fingerprints.InitFingerprint
|
||||
|
||||
@Patch(requiresIntegrations = true)
|
||||
object IntegrationsPatch : BaseIntegrationsPatch(
|
||||
setOf(InitFingerprint)
|
||||
)
|
|
@ -0,0 +1,10 @@
|
|||
package app.revanced.patches.reddit.customclients.syncforreddit.misc.integrations.fingerprints
|
||||
|
||||
import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint
|
||||
|
||||
internal object InitFingerprint : IntegrationsFingerprint(
|
||||
customFingerprint = { methodDef, classDef ->
|
||||
methodDef.name == "onCreate" && classDef.type == "Lcom/laurencedawson/reddit_sync/RedditApplication;"
|
||||
},
|
||||
insertIndexResolver = { 1 }, // Insert after call to super class.
|
||||
)
|
|
@ -1,6 +1,7 @@
|
|||
package app.revanced.patches.shared.misc.mapping
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
import org.w3c.dom.Element
|
||||
import java.util.*
|
||||
|
@ -51,9 +52,10 @@ object ResourceMappingPatch : ResourcePatch() {
|
|||
threadPoolExecutor.also { it.shutdown() }.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS)
|
||||
}
|
||||
|
||||
operator fun get(type: String, name: String) = resourceMappings.first {
|
||||
it.type == type && it.name == name
|
||||
}.id
|
||||
operator fun get(type: String, name: String) =
|
||||
resourceMappings.firstOrNull {
|
||||
it.type == type && it.name == name
|
||||
}?.id ?: throw PatchException("Could not find resource type: $type name: $name")
|
||||
|
||||
data class ResourceElement(val type: String, val name: String, val id: Long)
|
||||
}
|
||||
|
|
|
@ -62,9 +62,12 @@ object CommentsPatch : ResourcePatch() {
|
|||
PreferenceScreen(
|
||||
"revanced_comments_screen",
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_preview_comment"),
|
||||
SwitchPreference("revanced_hide_comments_by_members_header"),
|
||||
SwitchPreference("revanced_hide_comments_section"),
|
||||
SwitchPreference("revanced_hide_comment_timestamp_and_emoji_buttons")
|
||||
SwitchPreference("revanced_hide_comments_create_a_short_button"),
|
||||
SwitchPreference("revanced_hide_comments_preview_comment"),
|
||||
SwitchPreference("revanced_hide_comments_thanks_button"),
|
||||
SwitchPreference("revanced_hide_comments_timestamp_and_emoji_buttons")
|
||||
),
|
||||
sorting = PreferenceScreen.Sorting.UNSORTED
|
||||
)
|
||||
|
|
|
@ -94,10 +94,9 @@ object HideLayoutComponentsPatch : BytecodePatch(
|
|||
PreferenceScreen(
|
||||
key = "revanced_hide_description_components_screen",
|
||||
preferences = setOf(
|
||||
SwitchPreference("revanced_hide_chapters"),
|
||||
SwitchPreference("revanced_hide_attributes_section"),
|
||||
SwitchPreference("revanced_hide_chapters_section"),
|
||||
SwitchPreference("revanced_hide_info_cards_section"),
|
||||
SwitchPreference("revanced_hide_game_section"),
|
||||
SwitchPreference("revanced_hide_music_section"),
|
||||
SwitchPreference("revanced_hide_podcast_section"),
|
||||
SwitchPreference("revanced_hide_transcript_section"),
|
||||
),
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
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.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.InputType
|
||||
import app.revanced.patches.shared.misc.settings.preference.ListPreference
|
||||
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.TextPreference
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerClose
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerExpand
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerForwardButton
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.modernMiniplayerRewindButton
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.scrimOverlay
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch.ytOutlineXWhite24
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerDimensionsCalculatorParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernAddViewListenerFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernCloseButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernConstructorFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernExpandButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernExpandCloseDrawablesFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernForwardButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernOverlayViewFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernRewindButtonFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerModernViewParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerOverrideFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerOverrideNoContextFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.MiniplayerResponseModelSizeCheckFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||
import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.findOpcodeIndicesReversed
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
|
||||
// YT uses "Miniplayer" without a space between 'mini' and 'player: https://support.google.com/youtube/answer/9162927.
|
||||
@Patch(
|
||||
name = "Miniplayer",
|
||||
description = "Adds options to change the in app minimized player, " +
|
||||
"and if patching target 19.16+ adds options to use modern miniplayers.",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
MiniplayerResourcePatch::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube", [
|
||||
"18.32.39",
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43",
|
||||
"19.12.41",
|
||||
"19.13.37",
|
||||
// 19.14 is left out, as it has incomplete miniplayer code and missing some UI resources.
|
||||
// It's simpler to not bother with supporting this single old version.
|
||||
// 19.15 has a different code for handling sub title texts,
|
||||
// and also probably not worth making changes just to support this single old version.
|
||||
"19.16.39" // Earliest supported version with modern miniplayers.
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object MiniplayerPatch : BytecodePatch(
|
||||
setOf(GetFormFactorFingerprint,
|
||||
MiniplayerDimensionsCalculatorParentFingerprint,
|
||||
MiniplayerResponseModelSizeCheckFingerprint,
|
||||
MiniplayerOverrideFingerprint,
|
||||
MiniplayerModernConstructorFingerprint,
|
||||
MiniplayerModernViewParentFingerprint,
|
||||
YouTubePlayerOverlaysLayoutFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/MiniplayerPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
// Modern mini player is only present and functional in 19.15+.
|
||||
// Resource is not present in older versions. Using it to determine, if patching an old version.
|
||||
val isPatchingOldVersion = ytOutlinePictureInPictureWhite24 < 0
|
||||
|
||||
SettingsPatch.PreferenceScreen.PLAYER.addPreferences(
|
||||
PreferenceScreen(
|
||||
key = "revanced_miniplayer_screen",
|
||||
sorting = Sorting.UNSORTED,
|
||||
preferences =
|
||||
if (isPatchingOldVersion) {
|
||||
setOf(
|
||||
ListPreference(
|
||||
"revanced_miniplayer_type",
|
||||
summaryKey = null,
|
||||
entriesKey = "revanced_miniplayer_type_legacy_entries",
|
||||
entryValuesKey = "revanced_miniplayer_type_legacy_entry_values"
|
||||
)
|
||||
)
|
||||
} else {
|
||||
setOf(
|
||||
ListPreference(
|
||||
"revanced_miniplayer_type",
|
||||
summaryKey = null,
|
||||
entriesKey = "revanced_miniplayer_type_19_15_entries",
|
||||
entryValuesKey = "revanced_miniplayer_type_19_15_entry_values"
|
||||
),
|
||||
SwitchPreference("revanced_miniplayer_hide_expand_close"),
|
||||
SwitchPreference("revanced_miniplayer_hide_subtext"),
|
||||
SwitchPreference("revanced_miniplayer_hide_rewind_forward"),
|
||||
TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
// region Enable tablet miniplayer.
|
||||
|
||||
MiniplayerOverrideNoContextFingerprint.resolve(
|
||||
context,
|
||||
MiniplayerDimensionsCalculatorParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
MiniplayerOverrideNoContextFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Legacy tablet Miniplayer hooks.
|
||||
|
||||
MiniplayerOverrideFingerprint.resultOrThrow().let {
|
||||
val appNameStringIndex = it.scanResult.stringsScanResult!!.matches.first().index + 2
|
||||
|
||||
it.mutableMethod.apply {
|
||||
val walkerMethod = context.toMethodWalker(this)
|
||||
.nextMethod(appNameStringIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
|
||||
walkerMethod.apply {
|
||||
findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MiniplayerResponseModelSizeCheckFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.insertLegacyTabletMiniplayerOverride(it.scanResult.patternScanResult!!.endIndex)
|
||||
}
|
||||
|
||||
if (isPatchingOldVersion) {
|
||||
// Return here, as patch below is only intended for new versions of the app.
|
||||
return
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
|
||||
// region Enable modern miniplayer.
|
||||
|
||||
MiniplayerModernConstructorFingerprint.resultOrThrow().mutableClass.methods.forEach {
|
||||
it.apply {
|
||||
if (AccessFlags.CONSTRUCTOR.isSet(accessFlags)) {
|
||||
val iPutIndex = indexOfFirstInstructionOrThrow {
|
||||
this.opcode == Opcode.IPUT && this.getReference<FieldReference>()?.type == "I"
|
||||
}
|
||||
|
||||
insertModernMiniplayerTypeOverride(iPutIndex)
|
||||
} else {
|
||||
findReturnIndicesReversed().forEach { index -> insertModernMiniplayerOverride(index) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Fix 19.16 using mixed up drawables for tablet modern.
|
||||
// YT fixed this mistake in 19.17.
|
||||
// Fix this, by swapping the drawable resource values with each other.
|
||||
|
||||
MiniplayerModernExpandCloseDrawablesFingerprint.apply {
|
||||
resolve(
|
||||
context,
|
||||
MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
}.resultOrThrow().mutableMethod.apply {
|
||||
listOf(
|
||||
ytOutlinePictureInPictureWhite24 to ytOutlineXWhite24,
|
||||
ytOutlineXWhite24 to ytOutlinePictureInPictureWhite24,
|
||||
).forEach { (originalResource, replacementResource) ->
|
||||
val imageResourceIndex = indexOfFirstWideLiteralInstructionValueOrThrow(originalResource)
|
||||
val register = getInstruction<OneRegisterInstruction>(imageResourceIndex).registerA
|
||||
|
||||
replaceInstruction(imageResourceIndex, "const v$register, $replacementResource")
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
|
||||
// region Add hooks to hide tablet modern miniplayer buttons.
|
||||
|
||||
listOf(
|
||||
Triple(MiniplayerModernExpandButtonFingerprint, modernMiniplayerExpand,"hideMiniplayerExpandClose"),
|
||||
Triple(MiniplayerModernCloseButtonFingerprint, modernMiniplayerClose, "hideMiniplayerExpandClose"),
|
||||
Triple(MiniplayerModernRewindButtonFingerprint, modernMiniplayerRewindButton, "hideMiniplayerRewindForward"),
|
||||
Triple(MiniplayerModernForwardButtonFingerprint, modernMiniplayerForwardButton, "hideMiniplayerRewindForward"),
|
||||
Triple(MiniplayerModernOverlayViewFingerprint, scrimOverlay, "adjustMiniplayerOpacity")
|
||||
).forEach { (fingerprint, literalValue, methodName) ->
|
||||
fingerprint.resolve(
|
||||
context,
|
||||
MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
|
||||
fingerprint.hookInflatedView(
|
||||
literalValue,
|
||||
"Landroid/widget/ImageView;",
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
|
||||
)
|
||||
}
|
||||
|
||||
MiniplayerModernAddViewListenerFingerprint.apply {
|
||||
resolve(
|
||||
context,
|
||||
MiniplayerModernViewParentFingerprint.resultOrThrow().classDef
|
||||
)
|
||||
}.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->" +
|
||||
"hideMiniplayerSubTexts(Landroid/view/View;)V"
|
||||
)
|
||||
|
||||
|
||||
// Modern 2 has a broken overlay subtitle view that is always present.
|
||||
// Modern 2 uses the same overlay controls as the regular video player,
|
||||
// and the overlay views are added at runtime.
|
||||
// Add a hook to the overlay class, and pass the added views to integrations.
|
||||
YouTubePlayerOverlaysLayoutFingerprint.resultOrThrow().mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
|
||||
"addView",
|
||||
listOf(
|
||||
ImmutableMethodParameter("Landroid/view/View;", null, null),
|
||||
ImmutableMethodParameter("I", null, null),
|
||||
ImmutableMethodParameter("Landroid/view/ViewGroup\$LayoutParams;", null, null),
|
||||
),
|
||||
"V",
|
||||
AccessFlags.PUBLIC.value,
|
||||
null,
|
||||
null,
|
||||
MutableMethodImplementation(4),
|
||||
).toMutable().apply {
|
||||
addInstructions(
|
||||
"""
|
||||
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
|
||||
invoke-static { p1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
|
||||
return-void
|
||||
""",
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
// endregion
|
||||
}
|
||||
|
||||
private fun Method.findReturnIndicesReversed() = findOpcodeIndicesReversed(Opcode.RETURN)
|
||||
|
||||
/**
|
||||
* Adds an override to force legacy tablet miniplayer to be used or not used.
|
||||
*/
|
||||
private fun MutableMethod.insertLegacyTabletMiniplayerOverride(index: Int) {
|
||||
insertBooleanOverride(index, "getLegacyTabletMiniplayerOverride")
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an override to force modern miniplayer to be used or not used.
|
||||
*/
|
||||
private fun MutableMethod.insertModernMiniplayerOverride(index: Int) {
|
||||
insertBooleanOverride(index, "getModernMiniplayerOverride")
|
||||
}
|
||||
|
||||
private fun MutableMethod.insertBooleanOverride(index: Int, methodName: String) {
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
addInstructions(
|
||||
index,
|
||||
"""
|
||||
invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->$methodName(Z)Z
|
||||
move-result v$register
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an override to specify which modern miniplayer is used.
|
||||
*/
|
||||
private fun MutableMethod.insertModernMiniplayerTypeOverride(iPutIndex: Int) {
|
||||
val targetInstruction = getInstruction<TwoRegisterInstruction>(iPutIndex)
|
||||
val targetReference = (targetInstruction as ReferenceInstruction).reference
|
||||
|
||||
addInstructions(
|
||||
iPutIndex + 1, """
|
||||
invoke-static { v${targetInstruction.registerA} }, $INTEGRATIONS_CLASS_DESCRIPTOR->getModernMiniplayerOverrideType(I)I
|
||||
move-result v${targetInstruction.registerA}
|
||||
# Original instruction
|
||||
iput v${targetInstruction.registerA}, v${targetInstruction.registerB}, $targetReference
|
||||
"""
|
||||
)
|
||||
removeInstruction(iPutIndex)
|
||||
}
|
||||
|
||||
private fun LiteralValueFingerprint.hookInflatedView(
|
||||
literalValue: Long,
|
||||
hookedClassType: String,
|
||||
integrationsMethodName: String,
|
||||
) {
|
||||
resultOrThrow().mutableMethod.apply {
|
||||
val imageViewIndex = indexOfFirstInstructionOrThrow(
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(literalValue)
|
||||
) {
|
||||
opcode == Opcode.CHECK_CAST && getReference<TypeReference>()?.type == hookedClassType
|
||||
}
|
||||
|
||||
val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
|
||||
addInstruction(
|
||||
imageViewIndex + 1,
|
||||
"invoke-static { v$register }, $integrationsMethodName"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
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 MiniplayerResourcePatch : ResourcePatch() {
|
||||
var floatyBarButtonTopMargin = -1L
|
||||
|
||||
// Only available in 19.15 and upwards.
|
||||
var ytOutlineXWhite24 = -1L
|
||||
var ytOutlinePictureInPictureWhite24 = -1L
|
||||
var scrimOverlay = -1L
|
||||
var modernMiniplayerClose = -1L
|
||||
var modernMiniplayerExpand = -1L
|
||||
var modernMiniplayerRewindButton = -1L
|
||||
var modernMiniplayerForwardButton = -1L
|
||||
var playerOverlays = -1L
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
||||
floatyBarButtonTopMargin = ResourceMappingPatch[
|
||||
"dimen",
|
||||
"floaty_bar_button_top_margin"
|
||||
]
|
||||
|
||||
try {
|
||||
ytOutlinePictureInPictureWhite24 = ResourceMappingPatch[
|
||||
"drawable",
|
||||
"yt_outline_picture_in_picture_white_24"
|
||||
]
|
||||
} catch (exception: PatchException) {
|
||||
// Ignore, and assume the app is 19.14 or earlier.
|
||||
return
|
||||
}
|
||||
|
||||
ytOutlineXWhite24 = ResourceMappingPatch[
|
||||
"drawable",
|
||||
"yt_outline_x_white_24"
|
||||
]
|
||||
|
||||
scrimOverlay = ResourceMappingPatch[
|
||||
"id",
|
||||
"scrim_overlay"
|
||||
]
|
||||
|
||||
modernMiniplayerClose = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_close"
|
||||
]
|
||||
|
||||
modernMiniplayerExpand = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_expand"
|
||||
]
|
||||
|
||||
modernMiniplayerRewindButton = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_rewind_button"
|
||||
]
|
||||
|
||||
modernMiniplayerForwardButton = ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_forward_button"
|
||||
]
|
||||
|
||||
playerOverlays = ResourceMappingPatch[
|
||||
"layout",
|
||||
"player_overlays"
|
||||
]
|
||||
|
||||
// Resource id is not used during patching, but is used by integrations.
|
||||
// Verify the resource is present while patching.
|
||||
ResourceMappingPatch[
|
||||
"id",
|
||||
"modern_miniplayer_subtitle_text"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniplayerDimensionsCalculatorParentFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("L"),
|
||||
literalSupplier = { MiniplayerResourcePatch.floatyBarButtonTopMargin }
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernAddViewListenerFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroid/view/View;")
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernCloseButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerClose }
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniplayerModernConstructorFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
parameters = listOf("L"),
|
||||
literalSupplier = { 45623000L } // Magic number found in the constructor.
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernExpandButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerExpand }
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernExpandCloseDrawablesFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("L"),
|
||||
literalSupplier = { MiniplayerResourcePatch.ytOutlinePictureInPictureWhite24 }
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernForwardButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerForwardButton }
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernOverlayViewFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.scrimOverlay }
|
||||
)
|
|
@ -0,0 +1,16 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
/**
|
||||
* Resolves using the class found in [MiniplayerModernViewParentFingerprint].
|
||||
*/
|
||||
internal object MiniplayerModernRewindButtonFingerprint : LiteralValueFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Landroid/widget/ImageView;",
|
||||
parameters = listOf(),
|
||||
literalSupplier = { MiniplayerResourcePatch.modernMiniplayerRewindButton }
|
||||
)
|
|
@ -0,0 +1,12 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniplayerModernViewParentFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Ljava/lang/String;",
|
||||
parameters = listOf(),
|
||||
strings = listOf("player_overlay_modern_mini_player_controls")
|
||||
)
|
|
@ -1,10 +1,10 @@
|
|||
package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
|
||||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal object MiniPlayerOverrideFingerprint : MethodFingerprint(
|
||||
internal object MiniplayerOverrideFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
|
@ -0,0 +1,12 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.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 MiniplayerOverrideNoContextFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||
returnType = "Z",
|
||||
opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
|
||||
)
|
|
@ -1,15 +1,15 @@
|
|||
package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints
|
||||
package app.revanced.patches.youtube.layout.miniplayer.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 MiniPlayerResponseModelSizeCheckFingerprint : MethodFingerprint(
|
||||
"L",
|
||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||
listOf(
|
||||
internal object MiniplayerResponseModelSizeCheckFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "L",
|
||||
parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||
opcodes = listOf(
|
||||
Opcode.RETURN_OBJECT,
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.CHECK_CAST,
|
|
@ -0,0 +1,13 @@
|
|||
package app.revanced.patches.youtube.layout.miniplayer.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.youtube.layout.miniplayer.fingerprints.YouTubePlayerOverlaysLayoutFingerprint.YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||
|
||||
internal object YouTubePlayerOverlaysLayoutFingerprint : MethodFingerprint(
|
||||
customFingerprint = { _, classDef ->
|
||||
classDef.type == YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME
|
||||
}
|
||||
) {
|
||||
const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =
|
||||
"Lcom/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout;"
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package app.revanced.patches.youtube.layout.player.overlay
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
|
@ -9,6 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch
|
|||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patches.youtube.layout.player.overlay.fingerprints.CreatePlayerOverviewFingerprint
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
@Patch(
|
||||
|
@ -27,7 +27,7 @@ object CustomPlayerOverlayOpacityPatch : BytecodePatch(setOf(CreatePlayerOvervie
|
|||
CreatePlayerOverviewFingerprint.result?.let { result ->
|
||||
result.mutableMethod.apply {
|
||||
val viewRegisterIndex =
|
||||
indexOfFirstWideLiteralInstructionValue(CustomPlayerOverlayOpacityResourcePatch.scrimOverlayId) + 3
|
||||
indexOfFirstWideLiteralInstructionValueOrThrow(CustomPlayerOverlayOpacityResourcePatch.scrimOverlayId) + 3
|
||||
val viewRegister =
|
||||
getInstruction<OneRegisterInstruction>(viewRegisterIndex).registerA
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package app.revanced.patches.youtube.layout.seekbar
|
||||
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
|
@ -15,6 +13,8 @@ import app.revanced.patches.youtube.layout.seekbar.fingerprints.ShortsSeekbarCol
|
|||
import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch
|
||||
import app.revanced.patches.youtube.layout.theme.LithoColorHookPatch.lithoColorOverrideHook
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
|
||||
|
@ -30,7 +30,7 @@ internal object SeekbarColorBytecodePatch : BytecodePatch(
|
|||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
fun MutableMethod.addColorChangeInstructions(resourceId: Long) {
|
||||
val registerIndex = indexOfFirstWideLiteralInstructionValue(resourceId) + 2
|
||||
val registerIndex = indexOfFirstWideLiteralInstructionValueOrThrow(resourceId) + 2
|
||||
val colorRegister = getInstruction<OneRegisterInstruction>(registerIndex).registerA
|
||||
addInstructions(
|
||||
registerIndex + 1,
|
||||
|
|
|
@ -13,18 +13,51 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
|||
import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.resultOrThrow
|
||||
|
||||
@Patch(
|
||||
name = "Enable tablet layout",
|
||||
description = "Adds an option to spoof the device form factor to a tablet which enables the tablet layout.",
|
||||
dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
|
||||
compatiblePackages = [CompatiblePackage("com.google.android.youtube")]
|
||||
description = "Adds an option to enable tablet layout",
|
||||
dependencies = [
|
||||
IntegrationsPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class,
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube", arrayOf(
|
||||
"18.32.39",
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43",
|
||||
"19.12.41",
|
||||
"19.13.37",
|
||||
"19.14.43",
|
||||
"19.15.36",
|
||||
"19.16.39"
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object EnableTabletLayoutPatch : BytecodePatch(
|
||||
setOf(GetFormFactorFingerprint)
|
||||
) {
|
||||
object EnableTabletLayoutPatch : BytecodePatch(setOf(GetFormFactorFingerprint)) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/TabletLayoutPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
|
@ -32,7 +65,7 @@ object EnableTabletLayoutPatch : BytecodePatch(
|
|||
SwitchPreference("revanced_tablet_layout")
|
||||
)
|
||||
|
||||
GetFormFactorFingerprint.result?.let {
|
||||
GetFormFactorFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val returnIsLargeFormFactorIndex = getInstructions().lastIndex - 4
|
||||
val returnIsLargeFormFactorLabel = getInstruction(returnIsLargeFormFactorIndex)
|
||||
|
@ -40,8 +73,8 @@ object EnableTabletLayoutPatch : BytecodePatch(
|
|||
addInstructionsWithLabels(
|
||||
0,
|
||||
"""
|
||||
invoke-static { }, Lapp/revanced/integrations/youtube/patches/EnableTabletLayoutPatch;->enableTabletLayout()Z
|
||||
move-result v0 # Free register
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getTabletLayoutEnabled()Z
|
||||
move-result v0
|
||||
if-nez v0, :is_large_form_factor
|
||||
""",
|
||||
ExternalLabel(
|
||||
|
@ -50,6 +83,6 @@ object EnableTabletLayoutPatch : BytecodePatch(
|
|||
)
|
||||
)
|
||||
}
|
||||
} ?: GetFormFactorFingerprint.exception
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@ internal object GetFormFactorFingerprint : MethodFingerprint(
|
|||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.RETURN_OBJECT
|
||||
)
|
||||
),
|
||||
strings = listOf("")
|
||||
)
|
|
@ -1,152 +1,11 @@
|
|||
package app.revanced.patches.youtube.layout.tabletminiplayer
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerDimensionsCalculatorParentFingerprint
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideFingerprint
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideNoContextFingerprint
|
||||
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import app.revanced.patches.youtube.layout.miniplayer.MiniplayerPatch
|
||||
|
||||
@Patch(
|
||||
name = "Tablet mini player",
|
||||
description = "Adds an option to enable the tablet mini player layout.",
|
||||
dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube", arrayOf(
|
||||
"18.32.39",
|
||||
"18.37.36",
|
||||
"18.38.44",
|
||||
"18.43.45",
|
||||
"18.44.41",
|
||||
"18.45.43",
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43",
|
||||
"19.12.41",
|
||||
"19.13.37",
|
||||
"19.14.43",
|
||||
"19.15.36",
|
||||
"19.16.39",
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object TabletMiniPlayerPatch : BytecodePatch(
|
||||
setOf(
|
||||
MiniPlayerDimensionsCalculatorParentFingerprint,
|
||||
MiniPlayerResponseModelSizeCheckFingerprint,
|
||||
MiniPlayerOverrideFingerprint
|
||||
)
|
||||
) {
|
||||
@Deprecated("This patch class has been renamed to Miniplayer.")
|
||||
object TabletMiniPlayerPatch : BytecodePatch(dependencies = setOf(MiniplayerPatch::class)) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences(
|
||||
SwitchPreference("revanced_tablet_miniplayer")
|
||||
)
|
||||
|
||||
// First resolve the fingerprints via the parent fingerprint.
|
||||
MiniPlayerDimensionsCalculatorParentFingerprint.result
|
||||
?: throw MiniPlayerDimensionsCalculatorParentFingerprint.exception
|
||||
val miniPlayerClass = MiniPlayerDimensionsCalculatorParentFingerprint.result!!.classDef
|
||||
|
||||
/*
|
||||
* No context parameter method.
|
||||
*/
|
||||
MiniPlayerOverrideNoContextFingerprint.resolve(context, miniPlayerClass)
|
||||
val (method, _, parameterRegister) = MiniPlayerOverrideNoContextFingerprint.addProxyCall()
|
||||
|
||||
// Insert right before the return instruction.
|
||||
val secondInsertIndex = method.implementation!!.instructions.size - 1
|
||||
method.insertOverride(
|
||||
secondInsertIndex, parameterRegister
|
||||
/** same register used to return **/
|
||||
)
|
||||
|
||||
/*
|
||||
* Override every return instruction with the proxy call.
|
||||
*/
|
||||
MiniPlayerOverrideFingerprint.result?.let { result ->
|
||||
result.mutableMethod.let { method ->
|
||||
val appNameStringIndex = result.scanResult.stringsScanResult!!.matches.first().index + 2
|
||||
context.toMethodWalker(method).nextMethod(appNameStringIndex, true)
|
||||
.getMethod() as MutableMethod
|
||||
}.apply {
|
||||
implementation!!.let { implementation ->
|
||||
val returnIndices = implementation.instructions
|
||||
.withIndex()
|
||||
.filter { (_, instruction) -> instruction.opcode == Opcode.RETURN }
|
||||
.map { (index, _) -> index }
|
||||
|
||||
if (returnIndices.isEmpty()) throw PatchException("No return instructions found.")
|
||||
|
||||
// This method clobbers register p0 to return the value, calculate to override.
|
||||
val returnedRegister = implementation.registerCount - parameters.size
|
||||
|
||||
// Hook the returned register on every return instruction.
|
||||
returnIndices.forEach { index -> insertOverride(index, returnedRegister) }
|
||||
}
|
||||
}
|
||||
|
||||
return@let
|
||||
} ?: throw MiniPlayerOverrideFingerprint.exception
|
||||
|
||||
/*
|
||||
* Size check return value override.
|
||||
*/
|
||||
MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall()
|
||||
}
|
||||
|
||||
// Helper methods.
|
||||
private fun MethodFingerprint.addProxyCall(): Triple<MutableMethod, Int, Int> {
|
||||
val (method, scanIndex, parameterRegister) = this.unwrap()
|
||||
method.insertOverride(scanIndex, parameterRegister)
|
||||
|
||||
return Triple(method, scanIndex, parameterRegister)
|
||||
}
|
||||
|
||||
private fun MutableMethod.insertOverride(index: Int, overrideRegister: Int) {
|
||||
this.addInstructions(
|
||||
index,
|
||||
"""
|
||||
invoke-static {v$overrideRegister}, Lapp/revanced/integrations/youtube/patches/TabletMiniPlayerOverridePatch;->getTabletMiniPlayerOverride(Z)Z
|
||||
move-result v$overrideRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
private fun MethodFingerprint.unwrap(): Triple<MutableMethod, Int, Int> {
|
||||
val result = this.result!!
|
||||
val scanIndex = result.scanResult.patternScanResult!!.endIndex
|
||||
val method = result.mutableMethod
|
||||
val instructions = method.implementation!!.instructions
|
||||
val parameterRegister = (instructions[scanIndex] as OneRegisterInstruction).registerA
|
||||
|
||||
return Triple(method, scanIndex, parameterRegister)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.tabletminiplayer.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 MiniPlayerDimensionsCalculatorParentFingerprint : MethodFingerprint(
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "V",
|
||||
parameters = listOf("F"),
|
||||
opcodes = listOf(
|
||||
Opcode.CONST_HIGH16,
|
||||
Opcode.ADD_FLOAT_2ADDR,
|
||||
null, // Opcode.MUL_FLOAT or Opcode.MUL_FLOAT_2ADDR
|
||||
Opcode.CONST_4,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.MOVE_RESULT,
|
||||
Opcode.FLOAT_TO_INT,
|
||||
Opcode.INVOKE_INTERFACE,
|
||||
Opcode.RETURN_VOID,
|
||||
)
|
||||
)
|
|
@ -1,11 +0,0 @@
|
|||
package app.revanced.patches.youtube.layout.tabletminiplayer.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 MiniPlayerOverrideNoContextFingerprint : MethodFingerprint(
|
||||
"Z", AccessFlags.FINAL or AccessFlags.PRIVATE,
|
||||
opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction
|
||||
)
|
|
@ -16,7 +16,7 @@ import app.revanced.patches.youtube.layout.theme.fingerprints.UseGradientLoading
|
|||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.util.exception
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValue
|
||||
import app.revanced.util.indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
|
@ -123,7 +123,7 @@ object ThemeBytecodePatch : BytecodePatch(
|
|||
)
|
||||
|
||||
UseGradientLoadingScreenFingerprint.result?.mutableMethod?.apply {
|
||||
val isEnabledIndex = indexOfFirstWideLiteralInstructionValue(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3
|
||||
val isEnabledIndex = indexOfFirstWideLiteralInstructionValueOrThrow(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3
|
||||
val isEnabledRegister = getInstruction<OneRegisterInstruction>(isEnabledIndex - 1).registerA
|
||||
|
||||
addInstructions(
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
package app.revanced.patches.youtube.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.KidsBackgroundPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackManagerFingerprint
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.fingerprints.BackgroundPlaybackSettingsFingerprint
|
||||
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Patch(
|
||||
name = "Remove background playback restrictions",
|
||||
description = "Removes restrictions on background playback, including playing kids videos in the background.",
|
||||
dependencies = [
|
||||
BackgroundPlaybackResourcePatch::class,
|
||||
IntegrationsPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43",
|
||||
"19.12.41",
|
||||
"19.13.37",
|
||||
"19.14.43",
|
||||
"19.15.36",
|
||||
"19.16.39",
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object BackgroundPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
BackgroundPlaybackManagerFingerprint,
|
||||
BackgroundPlaybackSettingsFingerprint,
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/BackgroundPlaybackPatch;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
NonInteractivePreference("revanced_background_playback")
|
||||
)
|
||||
|
||||
BackgroundPlaybackManagerFingerprint.resultOrThrow().mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackIsNotShort()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
|
||||
// Enable background playback option in YouTube settings
|
||||
BackgroundPlaybackSettingsFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val booleanCalls = implementation!!.instructions.withIndex()
|
||||
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }
|
||||
|
||||
val settingsBooleanIndex = booleanCalls.elementAt(1).index
|
||||
val settingsBooleanMethod =
|
||||
context.toMethodWalker(this).nextMethod(settingsBooleanIndex, true).getMethod() as MutableMethod
|
||||
|
||||
settingsBooleanMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideBackgroundPlaybackAvailable()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// Force allowing background play for videos labeled for kids.
|
||||
KidsBackgroundPlaybackPolicyControllerFingerprint.resultOrThrow().mutableMethod.addInstruction(
|
||||
0,
|
||||
"return-void"
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package app.revanced.patches.youtube.misc.minimizedplayback
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback
|
||||
|
||||
import app.revanced.patcher.data.ResourceContext
|
||||
import app.revanced.patcher.patch.ResourcePatch
|
||||
|
@ -8,7 +8,7 @@ import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
|||
@Patch(
|
||||
dependencies = [ResourceMappingPatch::class],
|
||||
)
|
||||
internal object MinimizedPlaybackResourcePatch : ResourcePatch() {
|
||||
internal object BackgroundPlaybackResourcePatch : ResourcePatch() {
|
||||
internal var prefBackgroundAndOfflineCategoryId: Long = -1
|
||||
|
||||
override fun execute(context: ResourceContext) {
|
|
@ -1,11 +1,11 @@
|
|||
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback.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 MinimizedPlaybackManagerFingerprint : MethodFingerprint(
|
||||
internal object BackgroundPlaybackManagerFingerprint : MethodFingerprint(
|
||||
"Z",
|
||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||
listOf("L"),
|
|
@ -1,12 +1,12 @@
|
|||
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.MinimizedPlaybackResourcePatch
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackResourcePatch
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
|
||||
internal object BackgroundPlaybackSettingsFingerprint : LiteralValueFingerprint(
|
||||
returnType = "Ljava/lang/String;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf(),
|
||||
|
@ -19,5 +19,5 @@ internal object MinimizedPlaybackSettingsFingerprint : LiteralValueFingerprint(
|
|||
Opcode.IF_NEZ,
|
||||
Opcode.GOTO
|
||||
),
|
||||
literalSupplier = { MinimizedPlaybackResourcePatch.prefBackgroundAndOfflineCategoryId }
|
||||
literalSupplier = { BackgroundPlaybackResourcePatch.prefBackgroundAndOfflineCategoryId }
|
||||
)
|
|
@ -1,12 +1,11 @@
|
|||
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
|
||||
package app.revanced.patches.youtube.misc.backgroundplayback.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.util.patch.LiteralValueFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction
|
||||
|
||||
internal object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint(
|
||||
internal object KidsBackgroundPlaybackPolicyControllerFingerprint : LiteralValueFingerprint(
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("I", "L", "L"),
|
||||
|
@ -26,9 +25,5 @@ internal object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerp
|
|||
Opcode.INVOKE_VIRTUAL,
|
||||
Opcode.RETURN_VOID
|
||||
),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
methodDef.implementation!!.instructions.any {
|
||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 5)
|
||||
}
|
||||
}
|
||||
literalSupplier = { 5 },
|
||||
)
|
|
@ -286,9 +286,12 @@ object SpoofClientPatch : BytecodePatch(
|
|||
// Fix playback speed menu item if spoofing to iOS.
|
||||
|
||||
CreatePlaybackSpeedMenuItemFingerprint.resultOrThrow().let {
|
||||
val shouldCreateMenuIndex = it.scanResult.patternScanResult!!.endIndex
|
||||
val scanResult = it.scanResult.patternScanResult!!
|
||||
if (scanResult.startIndex != 0) throw PatchException("Unexpected start index: ${scanResult.startIndex}")
|
||||
|
||||
it.mutableMethod.apply {
|
||||
// Find the conditional check if the playback speed menu item is not created.
|
||||
val shouldCreateMenuIndex = indexOfFirstInstructionOrThrow(scanResult.endIndex) { opcode == Opcode.IF_EQZ }
|
||||
val shouldCreateMenuRegister = getInstruction<OneRegisterInstruction>(shouldCreateMenuIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
|
|
|
@ -8,11 +8,14 @@ import app.revanced.patches.all.misc.transformation.IMethodCall
|
|||
import app.revanced.patches.all.misc.transformation.Instruction35cInfo
|
||||
import app.revanced.patches.all.misc.transformation.filterMapInstruction35c
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.ClassDef
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
|
||||
object UserAgentClientSpoofPatch : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
||||
private const val ORIGINAL_PACKAGE_NAME = "com.google.android.youtube"
|
||||
|
@ -42,20 +45,31 @@ object UserAgentClientSpoofPatch : BaseTransformInstructionsPatch<Instruction35c
|
|||
as? OneRegisterInstruction ?: return
|
||||
).registerA
|
||||
|
||||
// IndexOutOfBoundsException is not possible here,
|
||||
// IndexOutOfBoundsException is possible here,
|
||||
// but no such occurrences are present in the app.
|
||||
val referee = getInstruction(instructionIndex + 2).getReference<MethodReference>()?.toString()
|
||||
|
||||
// This can technically also match non-user agent string builder append methods,
|
||||
// but no such occurrences are present in the app.
|
||||
// Only replace string builder usage.
|
||||
if (referee != USER_AGENT_STRING_BUILDER_APPEND_METHOD_REFERENCE) {
|
||||
return
|
||||
}
|
||||
|
||||
// Do not change the package name in methods that use resources, or for methods that use GmsCore.
|
||||
// Changing these package names will result in playback limitations,
|
||||
// particularly Android VR background audio only playback.
|
||||
val resourceOrGmsStringInstructionIndex = indexOfFirstInstruction {
|
||||
val reference = getReference<StringReference>()
|
||||
opcode == Opcode.CONST_STRING &&
|
||||
(reference?.string == "android.resource://" || reference?.string == "gcore_")
|
||||
}
|
||||
if (resourceOrGmsStringInstructionIndex >= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// Overwrite the result of context.getPackageName() with the original package name.
|
||||
replaceInstruction(
|
||||
instructionIndex + 1,
|
||||
"const-string v$targetRegister, \"${ORIGINAL_PACKAGE_NAME}\"",
|
||||
"const-string v$targetRegister, \"$ORIGINAL_PACKAGE_NAME\"",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,15 +8,27 @@ 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, // First instruction of the method
|
||||
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.
|
||||
null // MOVE_RESULT or MOVE_RESULT_OBJECT, Return value controls the creation of the playback speed menu item.
|
||||
),
|
||||
// 19.01 and earlier is missing the second parameter.
|
||||
// Since this fingerprint is somewhat weak, work around by checking for both method parameter signatures.
|
||||
customFingerprint = custom@{ methodDef, _ ->
|
||||
// 19.01 and earlier parameters are: "[L"
|
||||
// 19.02+ parameters are "[L", "F"
|
||||
val parameterTypes = methodDef.parameterTypes
|
||||
val firstParameter = parameterTypes.firstOrNull()
|
||||
|
||||
if (firstParameter == null || !firstParameter.startsWith("[L")) {
|
||||
return@custom false
|
||||
}
|
||||
|
||||
parameterTypes.size == 1 || (parameterTypes.size == 2 && parameterTypes[1] == "F")
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,117 +1,11 @@
|
|||
package app.revanced.patches.youtube.misc.minimizedplayback
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patcher.patch.annotation.CompatiblePackage
|
||||
import app.revanced.patcher.patch.annotation.Patch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.all.misc.resources.AddResourcesPatch
|
||||
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
|
||||
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
|
||||
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
|
||||
import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.util.exception
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
@Patch(
|
||||
name = "Minimized playback",
|
||||
description = "Unlocks options for picture-in-picture and background playback.",
|
||||
dependencies = [
|
||||
MinimizedPlaybackResourcePatch::class,
|
||||
IntegrationsPatch::class,
|
||||
PlayerTypeHookPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
SettingsPatch::class,
|
||||
AddResourcesPatch::class
|
||||
],
|
||||
compatiblePackages = [
|
||||
CompatiblePackage(
|
||||
"com.google.android.youtube",
|
||||
[
|
||||
"18.48.39",
|
||||
"18.49.37",
|
||||
"19.01.34",
|
||||
"19.02.39",
|
||||
"19.03.36",
|
||||
"19.04.38",
|
||||
"19.05.36",
|
||||
"19.06.39",
|
||||
"19.07.40",
|
||||
"19.08.36",
|
||||
"19.09.38",
|
||||
"19.10.39",
|
||||
"19.11.43",
|
||||
"19.12.41",
|
||||
"19.13.37",
|
||||
"19.14.43",
|
||||
"19.15.36",
|
||||
"19.16.39",
|
||||
]
|
||||
)
|
||||
]
|
||||
)
|
||||
@Suppress("unused")
|
||||
object MinimizedPlaybackPatch : BytecodePatch(
|
||||
setOf(
|
||||
MinimizedPlaybackManagerFingerprint,
|
||||
MinimizedPlaybackSettingsFingerprint,
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"Lapp/revanced/integrations/youtube/patches/MinimizedPlaybackPatch;"
|
||||
import app.revanced.patches.youtube.misc.backgroundplayback.BackgroundPlaybackPatch
|
||||
|
||||
@Deprecated("This patch class has been renamed to BackgroundPlaybackPatch.")
|
||||
object MinimizedPlaybackPatch : BytecodePatch(dependencies = setOf(BackgroundPlaybackPatch::class)) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
AddResourcesPatch(this::class)
|
||||
|
||||
SettingsPatch.PreferenceScreen.MISC.addPreferences(
|
||||
NonInteractivePreference("revanced_minimized_playback")
|
||||
)
|
||||
|
||||
MinimizedPlaybackManagerFingerprint.result?.apply {
|
||||
mutableMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->playbackIsNotShort()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
} ?: throw MinimizedPlaybackManagerFingerprint.exception
|
||||
|
||||
// Enable minimized playback option in YouTube settings
|
||||
MinimizedPlaybackSettingsFingerprint.result?.apply {
|
||||
val booleanCalls = method.implementation!!.instructions.withIndex()
|
||||
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }
|
||||
|
||||
val settingsBooleanIndex = booleanCalls.elementAt(1).index
|
||||
val settingsBooleanMethod =
|
||||
context.toMethodWalker(method).nextMethod(settingsBooleanIndex, true).getMethod() as MutableMethod
|
||||
|
||||
settingsBooleanMethod.addInstructions(
|
||||
0,
|
||||
"""
|
||||
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->overrideMinimizedPlaybackAvailable()Z
|
||||
move-result v0
|
||||
return v0
|
||||
"""
|
||||
)
|
||||
} ?: throw MinimizedPlaybackSettingsFingerprint.exception
|
||||
|
||||
// Force allowing background play for videos labeled for kids.
|
||||
// Some regions and YouTube accounts do not require this patch.
|
||||
KidsMinimizedPlaybackPolicyControllerFingerprint.result?.apply {
|
||||
mutableMethod.addInstruction(
|
||||
0,
|
||||
"return-void"
|
||||
)
|
||||
} ?: throw KidsMinimizedPlaybackPolicyControllerFingerprint.exception
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ import app.revanced.patcher.patch.PatchException
|
|||
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
|
@ -99,6 +100,7 @@ fun Method.indexOfIdResourceOrThrow(resourceName: String): Int {
|
|||
* Find the index of the first wide literal instruction with the given value.
|
||||
*
|
||||
* @return the first literal instruction with the value, or -1 if not found.
|
||||
* @see indexOfFirstWideLiteralInstructionValueOrThrow
|
||||
*/
|
||||
fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementation?.let {
|
||||
it.instructions.indexOfFirst { instruction ->
|
||||
|
@ -106,6 +108,18 @@ fun Method.indexOfFirstWideLiteralInstructionValue(literal: Long) = implementati
|
|||
}
|
||||
} ?: -1
|
||||
|
||||
/**
|
||||
* Find the index of the first wide literal instruction with the given value,
|
||||
* or throw an exception if not found.
|
||||
*
|
||||
* @return the first literal instruction with the value, or throws [PatchException] if not found.
|
||||
*/
|
||||
fun Method.indexOfFirstWideLiteralInstructionValueOrThrow(literal: Long) : Int {
|
||||
val index = indexOfFirstWideLiteralInstructionValue(literal)
|
||||
if (index < 0) throw PatchException("Could not find literal value: $literal")
|
||||
return index
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the method contains a literal with the given value.
|
||||
*
|
||||
|
@ -144,7 +158,9 @@ inline fun <reified T : Reference> Instruction.getReference() = (this as? Refere
|
|||
* @return The index of the first [Instruction] that matches the predicate.
|
||||
*/
|
||||
// TODO: delete this on next major release, the overloaded method with an optional start index serves the same purposes.
|
||||
@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
|
||||
// Method is deprecated, but annotation is commented out otherwise during compilation usage of the replacement is
|
||||
// incorrectly flagged as deprecated.
|
||||
//@Deprecated("Use the overloaded method with an optional start index.", ReplaceWith("indexOfFirstInstruction(predicate)"))
|
||||
fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = indexOfFirstInstruction(0, predicate)
|
||||
|
||||
/**
|
||||
|
@ -179,6 +195,21 @@ fun Method.indexOfFirstInstructionOrThrow(startIndex: Int = 0, predicate: Instru
|
|||
return index
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The list of indices of the opcode in reverse order.
|
||||
*/
|
||||
fun Method.findOpcodeIndicesReversed(opcode: Opcode): List<Int> {
|
||||
val indexes = implementation!!.instructions
|
||||
.withIndex()
|
||||
.filter { (_, instruction) -> instruction.opcode == opcode }
|
||||
.map { (index, _) -> index }
|
||||
.reversed()
|
||||
|
||||
if (indexes.isEmpty()) throw PatchException("No ${opcode.name} instructions found in: $this")
|
||||
|
||||
return indexes
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the resolved methods of [MethodFingerprint]s early.
|
||||
*/
|
||||
|
|
|
@ -16,6 +16,35 @@
|
|||
<item>17.33.42</item>
|
||||
</string-array>
|
||||
</patch>
|
||||
<patch id="layout.miniplayer.MiniplayerPatch">
|
||||
<string-array name="revanced_miniplayer_type_19_15_entries">
|
||||
<item>@string/revanced_miniplayer_type_entry_1</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_2</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_3</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_4</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_5</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_6</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_miniplayer_type_19_15_entry_values">
|
||||
<!-- Enum names from Integrations. -->
|
||||
<item>ORIGINAL</item>
|
||||
<item>PHONE</item>
|
||||
<item>TABLET</item>
|
||||
<item>MODERN_1</item>
|
||||
<item>MODERN_2</item>
|
||||
<item>MODERN_3</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_miniplayer_type_legacy_entries">
|
||||
<item>@string/revanced_miniplayer_type_entry_1</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_2</item>
|
||||
<item>@string/revanced_miniplayer_type_entry_3</item>
|
||||
</string-array>
|
||||
<string-array name="revanced_miniplayer_type_legacy_entry_values">
|
||||
<item>ORIGINAL</item>
|
||||
<item>PHONE</item>
|
||||
<item>TABLET</item>
|
||||
</string-array>
|
||||
</patch>
|
||||
<patch id="layout.startpage.ChangeStartPagePatch">
|
||||
<string-array name="revanced_start_page_entries">
|
||||
<item>@string/revanced_start_page_entry_0</item>
|
||||
|
|
|
@ -198,22 +198,19 @@
|
|||
<string name="revanced_hide_chips_shelf_title">Hide chips shelf</string>
|
||||
<string name="revanced_hide_chips_shelf_summary_on">Chips shelf is hidden</string>
|
||||
<string name="revanced_hide_chips_shelf_summary_off">Chips shelf is shown</string>
|
||||
<string name="revanced_hide_attributes_section_title">Hide attributes section</string>
|
||||
<string name="revanced_hide_attributes_section_summary_on">\'Featured places\', Games and Music sections are hidden</string>
|
||||
<string name="revanced_hide_attributes_section_summary_off">\'Featured places\', Games and Music sections are shown</string>
|
||||
<string name="revanced_hide_chapters_section_title">Hide Chapters section</string>
|
||||
<string name="revanced_hide_chapters_section_summary_on">Chapters section is hidden</string>
|
||||
<string name="revanced_hide_chapters_section_summary_off">Chapters section is shown</string>
|
||||
<string name="revanced_hide_podcast_section_title">Hide \'Explore the podcast\' section</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">\'Explore the podcast\' section is hidden</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">\'Explore the podcast\' section is shown</string>
|
||||
<string name="revanced_hide_info_cards_section_title">Hide info cards section</string>
|
||||
<string name="revanced_hide_info_cards_section_summary_on">Info cards section is hidden</string>
|
||||
<string name="revanced_hide_info_cards_section_summary_off">Info cards section is shown</string>
|
||||
<string name="revanced_hide_chapters_title">Hide chapters</string>
|
||||
<string name="revanced_hide_chapters_summary_on">Chapters are hidden</string>
|
||||
<string name="revanced_hide_chapters_summary_off">Chapters are shown</string>
|
||||
<string name="revanced_hide_game_section_title">Hide game section</string>
|
||||
<string name="revanced_hide_game_section_summary_on">Game section is hidden</string>
|
||||
<string name="revanced_hide_game_section_summary_off">Game section is shown</string>
|
||||
<string name="revanced_hide_music_section_title">Hide music section</string>
|
||||
<string name="revanced_hide_music_section_summary_on">Music section is hidden</string>
|
||||
<string name="revanced_hide_music_section_summary_off">Music section is shown</string>
|
||||
<string name="revanced_hide_podcast_section_title">Hide podcast section</string>
|
||||
<string name="revanced_hide_podcast_section_summary_on">Podcast section is hidden</string>
|
||||
<string name="revanced_hide_podcast_section_summary_off">Podcast section is shown</string>
|
||||
<string name="revanced_hide_transcript_section_title">Hide transcript section</string>
|
||||
<string name="revanced_hide_transcript_section_title">Hide Transcript section</string>
|
||||
<string name="revanced_hide_transcript_section_summary_on">Transcript section is hidden</string>
|
||||
<string name="revanced_hide_transcript_section_summary_off">Transcript section is shown</string>
|
||||
<string name="revanced_hide_description_components_screen_title">Video description</string>
|
||||
|
@ -502,15 +499,24 @@
|
|||
<patch id="layout.hide.comments.CommentsPatch">
|
||||
<string name="revanced_comments_screen_title">Comments</string>
|
||||
<string name="revanced_comments_screen_summary">Hide or show comments section components</string>
|
||||
<string name="revanced_hide_preview_comment_title">Hide preview comment</string>
|
||||
<string name="revanced_hide_preview_comment_summary_on">Preview comment is hidden</string>
|
||||
<string name="revanced_hide_preview_comment_summary_off">Preview comment is shown</string>
|
||||
<string name="revanced_hide_comments_by_members_header_title">Hide \'Comments by members\' header</string>
|
||||
<string name="revanced_hide_comments_by_members_header_summary_on">\'Comments by members\' header is hidden</string>
|
||||
<string name="revanced_hide_comments_by_members_header_summary_off">\'Comments by members\' header is shown</string>
|
||||
<string name="revanced_hide_comments_section_title">Hide comments section</string>
|
||||
<string name="revanced_hide_comments_section_summary_on">Comment section is hidden</string>
|
||||
<string name="revanced_hide_comments_section_summary_off">Comment section is shown</string>
|
||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_title">Hide timestamp and emoji buttons</string>
|
||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary_on">Comment timestamp and emoji buttons are hidden</string>
|
||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary_off">Comment timestamp and emoji buttons are shown</string>
|
||||
<string name="revanced_hide_comments_section_summary_on">Comments section is hidden</string>
|
||||
<string name="revanced_hide_comments_section_summary_off">Comments section is shown</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_title">Hide \'Create a Short\' button</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_summary_on">\'Create a Short\' button is hidden</string>
|
||||
<string name="revanced_hide_comments_create_a_short_button_summary_off">\'Create a Short\' button is shown</string>
|
||||
<string name="revanced_hide_comments_preview_comment_title">Hide preview comment</string>
|
||||
<string name="revanced_hide_comments_preview_comment_summary_on">Preview comment is hidden</string>
|
||||
<string name="revanced_hide_comments_preview_comment_summary_off">Preview comment is shown</string>
|
||||
<string name="revanced_hide_comments_thanks_button_title">Hide thanks button</string>
|
||||
<string name="revanced_hide_comments_thanks_button_summary_on">Thanks button is hidden</string>
|
||||
<string name="revanced_hide_comments_thanks_button_summary_off">Thanks button is shown</string>
|
||||
<string name="revanced_hide_comments_timestamp_and_emoji_buttons_title">Hide timestamp and emoji buttons</string>
|
||||
<string name="revanced_hide_comments_timestamp_and_emoji_buttons_summary_on">Timestamp and emoji buttons are hidden</string>
|
||||
<string name="revanced_hide_comments_timestamp_and_emoji_buttons_summary_off">Timestamp and emoji buttons are shown</string>
|
||||
</patch>
|
||||
<patch id="layout.hide.crowdfundingbox.CrowdfundingBoxResourcePatch">
|
||||
<string name="revanced_hide_crowdfunding_box_title">Hide crowdfunding box</string>
|
||||
|
@ -661,6 +667,7 @@
|
|||
<patch id="layout.player.overlay.CustomPlayerOverlayOpacityResourcePatch">
|
||||
<string name="revanced_player_overlay_opacity_title">Player overlay opacity</string>
|
||||
<string name="revanced_player_overlay_opacity_summary">Opacity value between 0-100, where 0 is transparent</string>
|
||||
<string name="revanced_player_overlay_opacity_invalid_toast">Player overlay opacity must be between 0-100</string>
|
||||
</patch>
|
||||
<patch id="layout.returnyoutubedislike.ReturnYouTubeDislikeResourcePatch">
|
||||
<string name="revanced_ryd_settings_title">Return YouTube Dislike</string>
|
||||
|
@ -947,11 +954,29 @@
|
|||
<string name="revanced_tablet_layout_summary_on">Tablet layout is enabled</string>
|
||||
<string name="revanced_tablet_layout_summary_off">Tablet layout is disabled</string>
|
||||
<string name="revanced_tablet_layout_user_dialog_message">Community posts do not show up on tablet layouts</string>
|
||||
</patch>
|
||||
<patch id="layout.tabletminiplayer.TabletMiniPlayerPatch">
|
||||
<string name="revanced_tablet_miniplayer_title">Enable tablet mini player</string>
|
||||
<string name="revanced_tablet_miniplayer_summary_on">Mini player is enabled</string>
|
||||
<string name="revanced_tablet_miniplayer_summary_off">Mini player is disabled</string>
|
||||
</patch>x
|
||||
<patch id="layout.miniplayer.MiniplayerPatch">
|
||||
<string name="revanced_miniplayer_screen_title">Miniplayer</string>
|
||||
<string name="revanced_miniplayer_screen_summary">Change the style of the in app minimized player</string>
|
||||
<string name="revanced_miniplayer_type_title">Miniplayer type</string>
|
||||
<string name="revanced_miniplayer_type_entry_1">Original</string>
|
||||
<string name="revanced_miniplayer_type_entry_2">Phone</string>
|
||||
<string name="revanced_miniplayer_type_entry_3">Tablet</string>
|
||||
<string name="revanced_miniplayer_type_entry_4">Modern 1</string>
|
||||
<string name="revanced_miniplayer_type_entry_5">Modern 2</string>
|
||||
<string name="revanced_miniplayer_type_entry_6">Modern 3</string>
|
||||
<string name="revanced_miniplayer_hide_expand_close_title">Hide expand and close buttons</string>
|
||||
<string name="revanced_miniplayer_hide_expand_close_summary_on">Buttons are hidden\n(swipe miniplayer to expand or close)</string>
|
||||
<string name="revanced_miniplayer_hide_expand_close_summary_off">Expand and close buttons are shown</string>
|
||||
<string name="revanced_miniplayer_hide_subtext_title">Hide subtexts</string>
|
||||
<string name="revanced_miniplayer_hide_subtext_summary_on">Subtexts are hidden</string>
|
||||
<string name="revanced_miniplayer_hide_subtext_summary_off">Subtexts are shown</string>
|
||||
<string name="revanced_miniplayer_hide_rewind_forward_title">Hide skip forward and back buttons</string>
|
||||
<string name="revanced_miniplayer_hide_rewind_forward_summary_on">Skip forward and back are hidden</string>
|
||||
<string name="revanced_miniplayer_hide_rewind_forward_summary_off">Skip forward and back are shown</string>
|
||||
<string name="revanced_miniplayer_opacity_title">Overlay opacity</string>
|
||||
<string name="revanced_miniplayer_opacity_summary">Opacity value between 0-100, where 0 is transparent</string>
|
||||
<string name="revanced_miniplayer_opacity_invalid_toast">Miniplayer overlay opacity must be between 0-100</string>
|
||||
</patch>
|
||||
<patch id="layout.theme.ThemeBytecodePatch">
|
||||
<string name="revanced_gradient_loading_screen_title">Enable gradient loading screen</string>
|
||||
|
@ -1032,9 +1057,9 @@
|
|||
<string name="revanced_external_browser_summary_on">Opening links externally</string>
|
||||
<string name="revanced_external_browser_summary_off">Opening links in app</string>
|
||||
</patch>
|
||||
<patch id="misc.minimizedplayback.MinimizedPlaybackPatch">
|
||||
<string name="revanced_minimized_playback_title">Minimized playback</string>
|
||||
<string name="revanced_minimized_playback_summary">This setting can be found in Settings -> Background</string>
|
||||
<patch id="misc.backgroundplayback.BackgroundPlaybackPatch">
|
||||
<string name="revanced_background_playback_title">Background playback</string>
|
||||
<string name="revanced_background_playback_summary">This setting can be found in Settings -> Background</string>
|
||||
</patch>
|
||||
<patch id="misc.privacy.RemoveTrackingQueryParameterPatch">
|
||||
<string name="revanced_remove_tracking_query_parameter_title">Remove tracking query parameter</string>
|
||||
|
@ -1101,7 +1126,7 @@
|
|||
<string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
|
||||
<string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
|
||||
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_on">Client is currently spoofed to iOS\n\nSide effects include:\n• No HDR video\n• 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• Higher video qualities may be missing\n• Live streams cannot play as audio only\n• Live streams not available on Android 8.0</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_off">Client is currently spoofed to Android VR\n\nSide effects include:\n• No HDR video\n• Kids videos do not playback\n• Paused videos can randomly resume</string>
|
||||
<string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
|
||||
<string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
|
||||
|
|
Loading…
Reference in a new issue