mirror of
https://github.com/ReVanced/revanced-patches.git
synced 2026-01-28 21:21:02 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93d4cee16e | ||
|
|
bc3b654357 | ||
|
|
64b4c92ca0 | ||
|
|
cd66ee4e57 | ||
|
|
f527226757 | ||
|
|
ec0b17a4d8 | ||
|
|
63598d0d42 | ||
|
|
14f6b66135 | ||
|
|
18893c005e | ||
|
|
73b51a0687 | ||
|
|
c4de003fc1 |
35
CHANGELOG.md
35
CHANGELOG.md
@@ -1,3 +1,38 @@
|
|||||||
|
## [2.9.1](https://github.com/revanced/revanced-patches/compare/v2.9.0...v2.9.1) (2022-07-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* make `minimized-playback-manager-fingerprint` unique ([#120](https://github.com/revanced/revanced-patches/issues/120)) ([cd5e911](https://github.com/revanced/revanced-patches/commit/cd5e911f4ed9ad95b02c13c30cd9466d250e8904))
|
||||||
|
|
||||||
|
# [2.9.0](https://github.com/revanced/revanced-patches/compare/v2.8.2...v2.9.0) (2022-07-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `swipe-controls` patch ([#115](https://github.com/revanced/revanced-patches/issues/115)) ([1d0a7dc](https://github.com/revanced/revanced-patches/commit/1d0a7dcc0cc3ea2bcd8ce0221d5e2f53d6eb0ae5))
|
||||||
|
|
||||||
|
## [2.8.2](https://github.com/revanced/revanced-patches/compare/v2.8.1...v2.8.2) (2022-07-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* show minimized playback options in settings ([#118](https://github.com/revanced/revanced-patches/issues/118)) ([6e1a538](https://github.com/revanced/revanced-patches/commit/6e1a538d34291d75f19bf66a188bc69241de3a7a))
|
||||||
|
|
||||||
|
## [2.8.1](https://github.com/revanced/revanced-patches/compare/v2.8.0...v2.8.1) (2022-07-05)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* remove unnecessary version constraints ([#117](https://github.com/revanced/revanced-patches/issues/117)) ([1cddf8d](https://github.com/revanced/revanced-patches/commit/1cddf8d9063da3bbdba0fd7080c8c93768b83a4c))
|
||||||
|
|
||||||
|
# [2.8.0](https://github.com/revanced/revanced-patches/compare/v2.7.0...v2.8.0) (2022-07-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `enable-debugging` patch ([#116](https://github.com/revanced/revanced-patches/issues/116)) ([bb355e7](https://github.com/revanced/revanced-patches/commit/bb355e7b7e78e602a10b346fe7e5795463615a81))
|
||||||
|
|
||||||
# [2.7.0](https://github.com/revanced/revanced-patches/compare/v2.6.0...v2.7.0) (2022-07-03)
|
# [2.7.0](https://github.com/revanced/revanced-patches/compare/v2.6.0...v2.7.0) (2022-07-03)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation(kotlin("stdlib"))
|
implementation(kotlin("stdlib"))
|
||||||
|
|
||||||
implementation("app.revanced:revanced-patcher:2.2.0")
|
implementation("app.revanced:revanced-patcher:2.3.0")
|
||||||
implementation("app.revanced:multidexlib2:2.5.2.r2")
|
implementation("app.revanced:multidexlib2:2.5.2.r2")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 2.7.0
|
version = 2.9.1
|
||||||
|
|||||||
@@ -1,7 +1,18 @@
|
|||||||
package app.revanced.extensions
|
package app.revanced.extensions
|
||||||
|
|
||||||
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.PatchResultError
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patcher.util.smali.toInstruction
|
import app.revanced.patcher.util.smali.toInstruction
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.MutableMethodImplementation
|
import org.jf.dexlib2.builder.MutableMethodImplementation
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction11n
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
|
||||||
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
||||||
import org.w3c.dom.Node
|
import org.w3c.dom.Node
|
||||||
|
|
||||||
internal fun MutableMethodImplementation.injectHideCall(
|
internal fun MutableMethodImplementation.injectHideCall(
|
||||||
@@ -14,6 +25,115 @@ internal fun MutableMethodImplementation.injectHideCall(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert an event hook at the top of the method. If the hook returns true, the event is consumed and the method will return with true
|
||||||
|
*
|
||||||
|
* the hook method MUST return a boolean and MUST take two parameters, like so:
|
||||||
|
* fun hook(thisRef: Object, eventData: Object): Boolean {}
|
||||||
|
*
|
||||||
|
* The final injected code will resemble the following logic:
|
||||||
|
* if( YouHook(this, event) ) { return true; }
|
||||||
|
* ...
|
||||||
|
*
|
||||||
|
* @param hookRef reference to the hook method
|
||||||
|
*/
|
||||||
|
internal fun MutableMethod.injectConsumableEventHook(hookRef: ImmutableMethodReference) {
|
||||||
|
val isStaticMethod = AccessFlags.STATIC.isSet(this.accessFlags)
|
||||||
|
this.implementation?.let { impl ->
|
||||||
|
// create label to index 0 to continue to the normal program flow
|
||||||
|
val lblContinueNormalFlow = impl.newLabelForIndex(0)
|
||||||
|
|
||||||
|
// define registers
|
||||||
|
/** V0 */
|
||||||
|
val regV0 = 0
|
||||||
|
|
||||||
|
/** this */
|
||||||
|
val regP0 = impl.registerCount - this.parameters.size - (if (isStaticMethod) 0 else 1)
|
||||||
|
|
||||||
|
/** motionEvent */
|
||||||
|
val regP1 = regP0 + 1
|
||||||
|
|
||||||
|
// insert instructions at the start of the method:
|
||||||
|
// if( Hook(this, event) ) { return true; }
|
||||||
|
impl.addInstructions(
|
||||||
|
0, listOf(
|
||||||
|
// invoke-static { p0, p1 } <hook>
|
||||||
|
BuilderInstruction35c(
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
2,
|
||||||
|
regP0,
|
||||||
|
regP1,
|
||||||
|
0, 0, 0,
|
||||||
|
hookRef
|
||||||
|
),
|
||||||
|
|
||||||
|
// move-result v0
|
||||||
|
BuilderInstruction11x(
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
regV0
|
||||||
|
),
|
||||||
|
|
||||||
|
// if-eqz v0, :continue_normal_flow
|
||||||
|
BuilderInstruction21t(
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
regV0,
|
||||||
|
lblContinueNormalFlow
|
||||||
|
),
|
||||||
|
|
||||||
|
// const/4 v0, 0x1
|
||||||
|
BuilderInstruction11n(
|
||||||
|
Opcode.CONST_4,
|
||||||
|
regV0,
|
||||||
|
0x1
|
||||||
|
),
|
||||||
|
|
||||||
|
// return v0
|
||||||
|
BuilderInstruction11x(
|
||||||
|
Opcode.RETURN,
|
||||||
|
regV0
|
||||||
|
)
|
||||||
|
|
||||||
|
// :continue_normal_flow
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert instructions into a named method
|
||||||
|
*
|
||||||
|
* @param targetClass the name of the class of which the method is a member
|
||||||
|
* @param targetMethod the name of the method to insert into
|
||||||
|
* @param index index to insert the instructions at. If the index is negative, it is used as an offset to the last method (so -1 inserts at the end of the method)
|
||||||
|
* @param instructions the smali instructions to insert (they'll be compiled by MutableMethod.addInstructions)
|
||||||
|
*/
|
||||||
|
internal fun BytecodeData.injectIntoNamedMethod(
|
||||||
|
targetClass: String,
|
||||||
|
targetMethod: String,
|
||||||
|
index: Int,
|
||||||
|
instructions: String
|
||||||
|
) {
|
||||||
|
var injections = 0
|
||||||
|
this.classes.filter { it.type.endsWith("$targetClass;") }.forEach { classDef ->
|
||||||
|
this.proxy(classDef).resolve().methods.filter { it.name == targetMethod }.forEach { methodDef ->
|
||||||
|
// if index is negative, interpret as an offset from the back
|
||||||
|
var insertIndex = index
|
||||||
|
if (insertIndex < 0) {
|
||||||
|
insertIndex += methodDef.implementation!!.instructions.size
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert instructions
|
||||||
|
methodDef.addInstructions(insertIndex, instructions)
|
||||||
|
injections++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail if nothing was injected
|
||||||
|
if (injections <= 0) {
|
||||||
|
throw PatchResultError("failed to inject into $targetClass.$targetMethod: no targets were found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal fun Node.doRecursively(action: (Node) -> Unit) {
|
internal fun Node.doRecursively(action: (Node) -> Unit) {
|
||||||
action(this)
|
action(this)
|
||||||
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action)
|
||||||
|
|||||||
@@ -45,9 +45,7 @@ import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
|||||||
@Description("Patch to remove general ads in bytecode.")
|
@Description("Patch to remove general ads in bytecode.")
|
||||||
@GeneralAdsCompatibility
|
@GeneralAdsCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class GeneralBytecodeAdsPatch : BytecodePatch(
|
class GeneralBytecodeAdsPatch : BytecodePatch() {
|
||||||
listOf()
|
|
||||||
) {
|
|
||||||
// a constant used by litho
|
// a constant used by litho
|
||||||
private val lithoConstant = 0xaed2868
|
private val lithoConstant = 0xaed2868
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package app.revanced.patches.youtube.interaction.fenster.annotation
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
//TODO the patch may be compatible with more versions, but this is the one i'm testing on right now...
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.google.android.youtube", arrayOf("17.24.34")
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class FensterCompatibility
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package app.revanced.patches.youtube.interaction.fenster.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patches.youtube.interaction.fenster.annotation.FensterCompatibility
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
@Name("update-player-type-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"LYoutubePlayerOverlaysLayout;",
|
||||||
|
"nM"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2)
|
||||||
|
@FensterCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object UpdatePlayerTypeFingerprint : MethodFingerprint(
|
||||||
|
"V",
|
||||||
|
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
null,
|
||||||
|
listOf(
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.IF_NE,
|
||||||
|
Opcode.RETURN_VOID,
|
||||||
|
Opcode.IPUT_OBJECT,
|
||||||
|
Opcode.INVOKE_DIRECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.RETURN_VOID,
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.RETURN_VOID
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package app.revanced.patches.youtube.interaction.fenster.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.injectConsumableEventHook
|
||||||
|
import app.revanced.extensions.injectIntoNamedMethod
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
|
import app.revanced.patcher.extensions.addInstruction
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultError
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.Dependencies
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
|
import app.revanced.patches.youtube.interaction.fenster.annotation.FensterCompatibility
|
||||||
|
import app.revanced.patches.youtube.interaction.fenster.fingerprints.UpdatePlayerTypeFingerprint
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
|
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("fenster-swipe-controls")
|
||||||
|
@Description("volume and brightness swipe controls")
|
||||||
|
@FensterCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
@Dependencies(dependencies = [IntegrationsPatch::class])
|
||||||
|
class FensterPatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
UpdatePlayerTypeFingerprint
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
|
// hook WatchWhileActivity.onStart (main activity lifecycle hook)
|
||||||
|
data.injectIntoNamedMethod(
|
||||||
|
"com/google/android/apps/youtube/app/watchwhile/WatchWhileActivity",
|
||||||
|
"onStart",
|
||||||
|
0,
|
||||||
|
"invoke-static { p0 }, Lapp/revanced/integrations/patches/FensterSwipePatch;->WatchWhileActivity_onStartHookEX(Ljava/lang/Object;)V"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hook YoutubePlayerOverlaysLayout.onFinishInflate (player overlays init hook)
|
||||||
|
data.injectIntoNamedMethod(
|
||||||
|
"com/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout",
|
||||||
|
"onFinishInflate",
|
||||||
|
-2,
|
||||||
|
"invoke-static { p0 }, Lapp/revanced/integrations/patches/FensterSwipePatch;->YouTubePlayerOverlaysLayout_onFinishInflateHookEX(Ljava/lang/Object;)V"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hook YoutubePlayerOverlaysLayout.UpdatePlayerType
|
||||||
|
injectUpdatePlayerTypeHook(
|
||||||
|
UpdatePlayerTypeFingerprint.result!!,
|
||||||
|
"com/google/android/apps/youtube/app/common/player/overlay/YouTubePlayerOverlaysLayout"
|
||||||
|
)
|
||||||
|
|
||||||
|
// hook NextGenWatchLayout.onTouchEvent and NextGenWatchLayout.onInterceptTouchEvent (player touch event hook)
|
||||||
|
injectWatchLayoutTouchHooks(
|
||||||
|
data,
|
||||||
|
"com/google/android/apps/youtube/app/watch/nextgenwatch/ui/NextGenWatchLayout"
|
||||||
|
)
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
|
private fun injectUpdatePlayerTypeHook(fingerPrintResult: MethodFingerprintResult, targetClass: String) {
|
||||||
|
// validate fingerprint found the right class
|
||||||
|
if (!fingerPrintResult.classDef.type.endsWith("$targetClass;")) {
|
||||||
|
throw PatchResultError("$targetClass.UpdatePlayerType fingerprint could not be validated")
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the hook
|
||||||
|
fingerPrintResult.mutableMethod.addInstruction(
|
||||||
|
0,
|
||||||
|
"invoke-static { p1 }, Lapp/revanced/integrations/patches/FensterSwipePatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inject onTouch event hooks into the watch layout class
|
||||||
|
*
|
||||||
|
* @param data bytecode data
|
||||||
|
* @param targetClass watch layout class name
|
||||||
|
*/
|
||||||
|
@Suppress("SameParameterValue")
|
||||||
|
private fun injectWatchLayoutTouchHooks(data: BytecodeData, targetClass: String) {
|
||||||
|
var touchHooksCount = 0
|
||||||
|
data.classes.filter { it.type.endsWith("$targetClass;") }.forEach { classDef ->
|
||||||
|
// hook onTouchEvent
|
||||||
|
data.proxy(classDef).resolve().methods.filter { it.name == "onTouchEvent" }.forEach { methodDef ->
|
||||||
|
touchHooksCount++
|
||||||
|
methodDef.injectConsumableEventHook(
|
||||||
|
ImmutableMethodReference(
|
||||||
|
"Lapp/revanced/integrations/patches/FensterSwipePatch;",
|
||||||
|
"NextGenWatchLayout_onTouchEventHookEX",
|
||||||
|
listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||||
|
"Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// hook onInterceptTouchEvent
|
||||||
|
data.proxy(classDef).resolve().methods.filter { it.name == "onInterceptTouchEvent" }.forEach { methodDef ->
|
||||||
|
touchHooksCount++
|
||||||
|
methodDef.injectConsumableEventHook(
|
||||||
|
ImmutableMethodReference(
|
||||||
|
"Lapp/revanced/integrations/patches/FensterSwipePatch;",
|
||||||
|
"NextGenWatchLayout_onInterceptTouchEventHookEX",
|
||||||
|
listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
|
||||||
|
"Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fail if no touch hooks were inserted
|
||||||
|
if (touchHooksCount <= 0) {
|
||||||
|
throw PatchResultError("failed to inject onTouchEvent hook into NextGenWatchLayout: none found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
|||||||
@Description("Patch to hide the cast button.")
|
@Description("Patch to hide the cast button.")
|
||||||
@CastButtonCompatibility
|
@CastButtonCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class HideCastButtonPatch : BytecodePatch(listOf()) {
|
class HideCastButtonPatch : BytecodePatch() {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
data.classes.forEach { classDef ->
|
data.classes.forEach { classDef ->
|
||||||
classDef.methods.forEach { method ->
|
classDef.methods.forEach { method ->
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.extensions.or
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
||||||
|
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
||||||
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
||||||
|
|
||||||
|
@Name("minimized-playback-manager-fingerprint")
|
||||||
|
@MatchingMethod(
|
||||||
|
"Ladj", "w"
|
||||||
|
)
|
||||||
|
@FuzzyPatternScanMethod(2)
|
||||||
|
@MinimizedPlaybackCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
|
||||||
|
"L",
|
||||||
|
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
null,
|
||||||
|
listOf(
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.IF_NEZ,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.IGET_OBJECT,
|
||||||
|
Opcode.CHECK_CAST
|
||||||
|
),
|
||||||
|
)
|
||||||
@@ -3,14 +3,20 @@ package app.revanced.patches.youtube.layout.minimizedplayback.patch
|
|||||||
import app.revanced.patcher.annotation.Description
|
import app.revanced.patcher.annotation.Description
|
||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
|
||||||
import app.revanced.patcher.data.impl.BytecodeData
|
import app.revanced.patcher.data.impl.BytecodeData
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.data.impl.toMethodWalker
|
||||||
import app.revanced.patcher.patch.impl.BytecodePatch
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.impl.BytecodePatch
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
|
||||||
import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
|
import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
|
||||||
|
import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
|
||||||
|
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
|
||||||
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@@ -20,7 +26,7 @@ import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.Minimi
|
|||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class MinimizedPlaybackPatch : BytecodePatch(
|
class MinimizedPlaybackPatch : BytecodePatch(
|
||||||
listOf(
|
listOf(
|
||||||
MinimizedPlaybackManagerFingerprint
|
MinimizedPlaybackManagerFingerprint, MinimizedPlaybackSettingsFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(data: BytecodeData): PatchResult {
|
override fun execute(data: BytecodeData): PatchResult {
|
||||||
@@ -32,6 +38,22 @@ class MinimizedPlaybackPatch : BytecodePatch(
|
|||||||
return v0
|
return v0
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val method = MinimizedPlaybackSettingsFingerprint.result!!.mutableMethod
|
||||||
|
val booleanCalls = method.implementation!!.instructions.withIndex()
|
||||||
|
.filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" }
|
||||||
|
|
||||||
|
val settingsBooleanIndex = booleanCalls.elementAt(1).index
|
||||||
|
val settingsBooleanMethod =
|
||||||
|
data.toMethodWalker(method).nextMethod(settingsBooleanIndex, true).getMethod() as MutableMethod
|
||||||
|
|
||||||
|
settingsBooleanMethod.addInstructions(
|
||||||
|
0, """
|
||||||
|
const/4 v0, 0x1
|
||||||
|
return v0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.enabledebugging.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package(
|
||||||
|
"com.google.android.youtube", arrayOf()
|
||||||
|
)]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class EnableDebuggingCompatibility
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package app.revanced.patches.youtube.misc.enabledebugging.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.impl.ResourceData
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.patch.impl.ResourcePatch
|
||||||
|
import app.revanced.patches.youtube.misc.enabledebugging.annotations.EnableDebuggingCompatibility
|
||||||
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
|
@Patch(false)
|
||||||
|
@Name("enable-debugging")
|
||||||
|
@Description("Enable app debugging by patching the manifest file")
|
||||||
|
@EnableDebuggingCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class EnableDebuggingPatch : ResourcePatch() {
|
||||||
|
override fun execute(data: ResourceData): PatchResult {
|
||||||
|
// create an xml editor instance
|
||||||
|
data.xmlEditor["AndroidManifest.xml"].use { dom ->
|
||||||
|
// get the application node
|
||||||
|
val applicationNode = dom
|
||||||
|
.file
|
||||||
|
.getElementsByTagName("application")
|
||||||
|
.item(0) as Element
|
||||||
|
|
||||||
|
// set application as debuggable
|
||||||
|
applicationNode.setAttribute("android:debuggable", "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user