Compare commits
10 Commits
v2.158.0-d
...
v2.159.0-d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e67d27c4b0 | ||
|
|
2223b07dbe | ||
|
|
4e3c06684a | ||
|
|
aefc1f02a4 | ||
|
|
762e290658 | ||
|
|
17b046df60 | ||
|
|
8d57c555a0 | ||
|
|
8e4235af16 | ||
|
|
b3f9858402 | ||
|
|
bd9c89cdcc |
33
CHANGELOG.md
@@ -1,3 +1,36 @@
|
|||||||
|
# [2.159.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.159.0-dev.1...v2.159.0-dev.2) (2023-02-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* `spoof-wifi-connection` patch ([#1527](https://github.com/revanced/revanced-patches/issues/1527)) ([adce206](https://github.com/revanced/revanced-patches/commit/adce206d66e1f7017328fe68a5818d424f70e588))
|
||||||
|
|
||||||
|
# [2.159.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.158.0...v2.159.0-dev.1) (2023-02-01)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **youtube/custom-branding:** correct scaling, margin and images ([#1580](https://github.com/revanced/revanced-patches/issues/1580)) ([491c413](https://github.com/revanced/revanced-patches/commit/491c4138f0185664a9c5d3db9ebdf026ff4594e8))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **music:** bump patches compatibility to v5.41.50 ([#1551](https://github.com/revanced/revanced-patches/issues/1551)) ([0b1024a](https://github.com/revanced/revanced-patches/commit/0b1024ab754a3e2ce798a54cccda6f41f97069a5))
|
||||||
|
* **spotify-lite:** enable on-demand patch ([9f0de4f](https://github.com/revanced/revanced-patches/commit/9f0de4f5678e9f57baaf6ec788821641d75defdc))
|
||||||
|
|
||||||
|
# [2.158.0](https://github.com/revanced/revanced-patches/compare/v2.157.0...v2.158.0) (2023-01-29)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **youtube/microg-support:** replace new permission ([3d1cce5](https://github.com/revanced/revanced-patches/commit/3d1cce5b4ca54c622b863f24febeb03a6060033c))
|
||||||
|
* **youtube:** resolve duplicate preference keys ([#1550](https://github.com/revanced/revanced-patches/issues/1550)) ([aafdb89](https://github.com/revanced/revanced-patches/commit/aafdb891b2f0f243cb2d997a38ab3e6a7b46aba8))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **irplus:** `remove-ads` patch ([#1554](https://github.com/revanced/revanced-patches/issues/1554)) ([9943a52](https://github.com/revanced/revanced-patches/commit/9943a520d29ee89598b4aa6aba69ff83cb4768ce))
|
||||||
|
|
||||||
# [2.158.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.157.1-dev.2...v2.158.0-dev.1) (2023-01-28)
|
# [2.158.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.157.1-dev.2...v2.158.0-dev.1) (2023-01-28)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
14
README.md
@@ -46,7 +46,7 @@ The official Patch bundle provided by ReVanced and the community.
|
|||||||
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.03.36 |
|
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.03.36 |
|
||||||
| `minimized-playback` | Enables minimized and background playback. | 18.03.36 |
|
| `minimized-playback` | Enables minimized and background playback. | 18.03.36 |
|
||||||
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.03.36 |
|
| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.03.36 |
|
||||||
| `open-links-directly` | Bypasses https://youtube.com/redirect URLs. | 18.03.36 |
|
| `open-links-directly` | Skips over redirection URLs to external links. | 18.03.36 |
|
||||||
| `open-links-externally` | Open links outside of the app directly in your browser. | 18.03.36 |
|
| `open-links-externally` | Open links outside of the app directly in your browser. | 18.03.36 |
|
||||||
| `premium-heading` | Shows premium branding on the home screen. | all |
|
| `premium-heading` | Shows premium branding on the home screen. | all |
|
||||||
| `remember-playback-rate` | Adds the ability to remember the playback rate you chose in the video playback rate flyout. | 18.03.36 |
|
| `remember-playback-rate` | Adds the ability to remember the playback rate you chose in the video playback rate flyout. | 18.03.36 |
|
||||||
@@ -54,7 +54,7 @@ The official Patch bundle provided by ReVanced and the community.
|
|||||||
| `remove-player-button-background` | Removes the background from the video player buttons. | 18.03.36 |
|
| `remove-player-button-background` | Removes the background from the video player buttons. | 18.03.36 |
|
||||||
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.03.36 |
|
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.03.36 |
|
||||||
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.03.36 |
|
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.03.36 |
|
||||||
| `sponsorblock` | Integrate SponsorBlock. | 18.03.36 |
|
| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.03.36 |
|
||||||
| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.03.36 |
|
| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.03.36 |
|
||||||
| `swipe-controls` | Adds volume and brightness swipe controls. | 18.03.36 |
|
| `swipe-controls` | Adds volume and brightness swipe controls. | 18.03.36 |
|
||||||
| `tablet-mini-player` | Enables the tablet mini player layout. | 18.03.36 |
|
| `tablet-mini-player` | Enables the tablet mini player layout. | 18.03.36 |
|
||||||
@@ -160,7 +160,7 @@ The official Patch bundle provided by ReVanced and the community.
|
|||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|:--------:|:--------------:|:-----------------:|
|
||||||
| `remove-bootloader-detection` | Removes the check for an unlocked bootloader. | 2.2.0 |
|
| `remove-bootloader-detection` | Removes the check for an unlocked bootloader. | 2.2.0 |
|
||||||
| `remove-root-detection` | Removes the check for root permissions | 2.2.0 |
|
| `remove-root-detection` | Removes the check for root permissions. | 2.2.0 |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### [📦 `at.gv.oe.app`](https://play.google.com/store/apps/details?id=at.gv.oe.app)
|
### [📦 `at.gv.oe.app`](https://play.google.com/store/apps/details?id=at.gv.oe.app)
|
||||||
@@ -188,6 +188,14 @@ The official Patch bundle provided by ReVanced and the community.
|
|||||||
| `disable-ads` | Disables ads in HexEditor. | all |
|
| `disable-ads` | Disables ads in HexEditor. | all |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### [📦 `com.spotify.lite`](https://play.google.com/store/apps/details?id=com.spotify.lite)
|
||||||
|
<details>
|
||||||
|
|
||||||
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|
|:--------:|:--------------:|:-----------------:|
|
||||||
|
| `enable-on-demand` | Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads. | all |
|
||||||
|
</details>
|
||||||
|
|
||||||
### [📦 `org.citra.citra_emu`](https://play.google.com/store/apps/details?id=org.citra.citra_emu)
|
### [📦 `org.citra.citra_emu`](https://play.google.com/store/apps/details?id=org.citra.citra_emu)
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
version = 2.158.0-dev.1
|
version = 2.159.0-dev.2
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
package app.revanced.patches.all.connectivity.wifi.spoof.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.util.patch.*
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@Patch(false)
|
||||||
|
@Name("spoof-wifi-connection")
|
||||||
|
@Description("Spoofs an existing Wi-Fi connection.")
|
||||||
|
@Version("0.0.1")
|
||||||
|
internal class SpoofWifiPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/all/connectivity/wifi/spoof/SpoofWifiPatch"
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR = "${INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX};"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Information about method calls we want to replace
|
||||||
|
enum class MethodCall(
|
||||||
|
override val definedClassName: String,
|
||||||
|
override val methodName: String,
|
||||||
|
override val methodParams: Array<String>,
|
||||||
|
override val returnType: String,
|
||||||
|
): IMethodCall {
|
||||||
|
GetSystemService1(
|
||||||
|
"Landroid/content/Context;",
|
||||||
|
"getSystemService",
|
||||||
|
arrayOf("Ljava/lang/String;"),
|
||||||
|
"Ljava/lang/Object;",
|
||||||
|
),
|
||||||
|
GetSystemService2(
|
||||||
|
"Landroid/content/Context;",
|
||||||
|
"getSystemService",
|
||||||
|
arrayOf("Ljava/lang/Class;"),
|
||||||
|
"Ljava/lang/Object;",
|
||||||
|
),
|
||||||
|
GetActiveNetworkInfo(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"getActiveNetworkInfo",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
),
|
||||||
|
IsConnected(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"isConnected",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
IsConnectedOrConnecting(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"isConnectedOrConnecting",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
IsAvailable(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"isAvailable",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
GetState(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"getState",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/NetworkInfo\$State;",
|
||||||
|
),
|
||||||
|
GetDetailedState(
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
"getDetailedState",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/NetworkInfo\$DetailedState;",
|
||||||
|
),
|
||||||
|
IsActiveNetworkMetered(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"isActiveNetworkMetered",
|
||||||
|
arrayOf(),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
GetActiveNetwork(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"getActiveNetwork",
|
||||||
|
arrayOf(),
|
||||||
|
"Landroid/net/Network;",
|
||||||
|
),
|
||||||
|
GetNetworkInfo(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"getNetworkInfo",
|
||||||
|
arrayOf("Landroid/net/Network;"),
|
||||||
|
"Landroid/net/NetworkInfo;",
|
||||||
|
),
|
||||||
|
HasTransport(
|
||||||
|
"Landroid/net/NetworkCapabilities;",
|
||||||
|
"hasTransport",
|
||||||
|
arrayOf("I"),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
HasCapability(
|
||||||
|
"Landroid/net/NetworkCapabilities;",
|
||||||
|
"hasCapability",
|
||||||
|
arrayOf("I"),
|
||||||
|
"Z",
|
||||||
|
),
|
||||||
|
RegisterBestMatchingNetworkCallback(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerBestMatchingNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterDefaultNetworkCallback1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerDefaultNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterDefaultNetworkCallback2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerDefaultNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterNetworkCallback1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterNetworkCallback2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/app/PendingIntent;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RegisterNetworkCallback3(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"registerNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "I"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork3(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork4(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/app/PendingIntent;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
RequestNetwork5(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"requestNetwork",
|
||||||
|
arrayOf("Landroid/net/NetworkRequest;", "Landroid/net/ConnectivityManager\$NetworkCallback;", "Landroid/os/Handler;", "I"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
UnregisterNetworkCallback1(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"unregisterNetworkCallback",
|
||||||
|
arrayOf("Landroid/net/ConnectivityManager\$NetworkCallback;"),
|
||||||
|
"V",
|
||||||
|
),
|
||||||
|
UnregisterNetworkCallback2(
|
||||||
|
"Landroid/net/ConnectivityManager;",
|
||||||
|
"unregisterNetworkCallback",
|
||||||
|
arrayOf("Landroid/app/PendingIntent;"),
|
||||||
|
"V",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun filterMap(
|
||||||
|
classDef: ClassDef,
|
||||||
|
method: Method,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
) = filterMapInstruction35c<MethodCall>(
|
||||||
|
INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX,
|
||||||
|
classDef,
|
||||||
|
instruction,
|
||||||
|
instructionIndex
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun transform(mutableMethod: MutableMethod, entry: Instruction35cInfo) {
|
||||||
|
val (methodType, instruction, instructionIndex) = entry
|
||||||
|
methodType.replaceInvokeVirtualWithIntegrations(INTEGRATIONS_CLASS_DESCRIPTOR, mutableMethod, instruction, instructionIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,106 +1,57 @@
|
|||||||
package app.revanced.patches.all.screenshot.removerestriction.patch
|
package app.revanced.patches.all.screenshot.removerestriction.patch
|
||||||
|
|
||||||
import app.revanced.extensions.findMutableMethodOf
|
|
||||||
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.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.replaceInstruction
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
|
||||||
import app.revanced.patcher.patch.annotations.Patch
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import org.jf.dexlib2.Opcode
|
import app.revanced.util.patch.*
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
@Patch(false)
|
@Patch(false)
|
||||||
@Name("remove-screenshot-restriction")
|
@Name("remove-screenshot-restriction")
|
||||||
@Description("Removes the restriction of making screenshots.")
|
@Description("Removes the restriction of taking screenshots in apps that normally wouldn't allow it.")
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RemoveScreenshotRestrictionPatch : BytecodePatch() {
|
internal class RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch<Instruction35cInfo>() {
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch;"
|
const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX =
|
||||||
|
"Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch"
|
||||||
|
const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Information about method calls we want to replace
|
// Information about method calls we want to replace
|
||||||
private enum class MethodCall(
|
enum class MethodCall(
|
||||||
val definedClassName: String,
|
override val definedClassName: String,
|
||||||
val methodName: String,
|
override val methodName: String,
|
||||||
val replacementMethodDefinition: String
|
override val methodParams: Array<String>,
|
||||||
) {
|
override val returnType: String
|
||||||
|
): IMethodCall {
|
||||||
SetFlags(
|
SetFlags(
|
||||||
"Landroid/view/Window;",
|
"Landroid/view/Window;",
|
||||||
"setFlags",
|
"setFlags",
|
||||||
"setFlags(Landroid/view/Window;II)V",
|
arrayOf("I", "I"),
|
||||||
|
"V",
|
||||||
);
|
);
|
||||||
|
|
||||||
fun replaceInstruction(method: MutableMethod, instruction: Instruction35c, instructionIndex: Int) {
|
|
||||||
when (this) {
|
|
||||||
SetFlags -> {
|
|
||||||
method.replaceInstruction(
|
|
||||||
instructionIndex,
|
|
||||||
"invoke-static { v${instruction.registerC}, v${instruction.registerD}, v${instruction.registerE} }, ${INTEGRATIONS_CLASS_DESCRIPTOR}->${replacementMethodDefinition}"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
fun fromMethodReference(methodReference: MethodReference) = values().firstOrNull { search ->
|
|
||||||
search.definedClassName == methodReference.definingClass && search.methodName == methodReference.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun filterMap(
|
||||||
// Find all instructions where one of the methods is called
|
classDef: ClassDef,
|
||||||
buildMap {
|
method: Method,
|
||||||
context.classes.forEach { classDef ->
|
instruction: Instruction,
|
||||||
if (classDef.type == INTEGRATIONS_CLASS_DESCRIPTOR) {
|
instructionIndex: Int
|
||||||
// avoid infinite recursion
|
) = filterMapInstruction35c<MethodCall>(
|
||||||
return@forEach
|
INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX,
|
||||||
}
|
classDef,
|
||||||
|
instruction,
|
||||||
|
instructionIndex
|
||||||
|
)
|
||||||
|
|
||||||
classDef.methods.let { methods ->
|
override fun transform(mutableMethod: MutableMethod, entry: Instruction35cInfo) {
|
||||||
buildMap methodList@{
|
val (methodType, instruction, instructionIndex) = entry
|
||||||
methods.forEach methods@{ method ->
|
methodType.replaceInvokeVirtualWithIntegrations(INTEGRATIONS_CLASS_DESCRIPTOR, mutableMethod, instruction, instructionIndex)
|
||||||
with(method.implementation?.instructions ?: return@methods) {
|
|
||||||
ArrayDeque<Triple<MethodCall, Instruction35c, Int>>().also { patchIndices ->
|
|
||||||
this.forEachIndexed { index, instruction ->
|
|
||||||
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed
|
|
||||||
|
|
||||||
val invokeInstruction = instruction as Instruction35c
|
|
||||||
val methodRef = invokeInstruction.reference as MethodReference
|
|
||||||
val methodCall = MethodCall.fromMethodReference(methodRef) ?: return@forEachIndexed
|
|
||||||
|
|
||||||
patchIndices.add(Triple(methodCall, invokeInstruction, index))
|
|
||||||
}
|
|
||||||
}.also { if (it.isEmpty()) return@methods }.let { patches ->
|
|
||||||
put(method, patches)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.also { if (it.isEmpty()) return@forEach }.let { methodPatches ->
|
|
||||||
put(classDef, methodPatches)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.forEach { (classDef, methods) ->
|
|
||||||
// And finally replace the instructions...
|
|
||||||
with(context.proxy(classDef).mutableClass) {
|
|
||||||
methods.forEach { (method, patches) ->
|
|
||||||
val mutableMethod = findMutableMethodOf(method)
|
|
||||||
while (!patches.isEmpty()) {
|
|
||||||
val (methodType, instruction, instructionIndex) = patches.removeLast()
|
|
||||||
methodType.replaceInstruction(mutableMethod, instruction, instructionIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import app.revanced.patches.finanzonline.detection.shared.annotations.DetectionC
|
|||||||
|
|
||||||
@Patch
|
@Patch
|
||||||
@Name("remove-root-detection")
|
@Name("remove-root-detection")
|
||||||
@Description("Removes the check for root permissions")
|
@Description("Removes the check for root permissions.")
|
||||||
@DetectionCompatibility
|
@DetectionCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class RootDetectionPatch : BytecodePatch(
|
class RootDetectionPatch : BytecodePatch(
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import app.revanced.patcher.annotation.Package
|
|||||||
"5.36.51",
|
"5.36.51",
|
||||||
"5.38.53",
|
"5.38.53",
|
||||||
"5.39.52",
|
"5.39.52",
|
||||||
"5.40.51"
|
"5.40.51",
|
||||||
|
"5.41.50"
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package app.revanced.patches.spotify.lite.ondemand.annotations
|
||||||
|
|
||||||
|
import app.revanced.patcher.annotation.Compatibility
|
||||||
|
import app.revanced.patcher.annotation.Package
|
||||||
|
|
||||||
|
@Compatibility(
|
||||||
|
[Package("com.spotify.lite")]
|
||||||
|
)
|
||||||
|
@Target(AnnotationTarget.CLASS)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
internal annotation class OnDemandCompatibility
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package app.revanced.patches.spotify.lite.ondemand.fingerprints
|
||||||
|
|
||||||
|
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
|
||||||
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
|
@FuzzyPatternScanMethod(2)
|
||||||
|
object OnDemandFingerprint : MethodFingerprint(
|
||||||
|
"L",
|
||||||
|
parameters = listOf(),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.INVOKE_STATIC,
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.GOTO,
|
||||||
|
Opcode.SGET_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
Opcode.MOVE_RESULT,
|
||||||
|
Opcode.IPUT,
|
||||||
|
Opcode.RETURN_OBJECT
|
||||||
|
)
|
||||||
|
)
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package app.revanced.patches.spotify.lite.ondemand.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.toErrorResult
|
||||||
|
import app.revanced.patcher.annotation.Description
|
||||||
|
import app.revanced.patcher.annotation.Name
|
||||||
|
import app.revanced.patcher.annotation.Version
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.extensions.addInstruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.Patch
|
||||||
|
import app.revanced.patches.spotify.lite.ondemand.annotations.OnDemandCompatibility
|
||||||
|
import app.revanced.patches.spotify.lite.ondemand.fingerprints.OnDemandFingerprint
|
||||||
|
|
||||||
|
@Patch
|
||||||
|
@Name("enable-on-demand")
|
||||||
|
@Description("Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.")
|
||||||
|
@OnDemandCompatibility
|
||||||
|
@Version("0.0.1")
|
||||||
|
class OnDemandPatch : BytecodePatch(
|
||||||
|
listOf(
|
||||||
|
OnDemandFingerprint
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
OnDemandFingerprint.result?.apply {
|
||||||
|
val insertIndex = scanResult.patternScanResult!!.endIndex - 1
|
||||||
|
// Spoof a premium account
|
||||||
|
mutableMethod.addInstruction(insertIndex, "const/4 v0, 0x2")
|
||||||
|
} ?: return OnDemandFingerprint.toErrorResult()
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -46,7 +46,7 @@ import org.jf.dexlib2.iface.reference.StringReference
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
@Name("sponsorblock")
|
@Name("sponsorblock")
|
||||||
@Description("Integrate SponsorBlock.")
|
@Description("Integrates SponsorBlock which allows skipping video segments such as sponsored content.")
|
||||||
@SponsorBlockCompatibility
|
@SponsorBlockCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class SponsorBlockBytecodePatch : BytecodePatch(
|
class SponsorBlockBytecodePatch : BytecodePatch(
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
|||||||
@Patch
|
@Patch
|
||||||
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
|
||||||
@Name("open-links-directly")
|
@Name("open-links-directly")
|
||||||
@Description("Bypasses https://youtube.com/redirect URLs.")
|
@Description("Skips over redirection URLs to external links.")
|
||||||
@OpenLinksDirectlyCompatibility
|
@OpenLinksDirectlyCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class OpenLinksDirectlyPatch : BytecodePatch(
|
class OpenLinksDirectlyPatch : BytecodePatch(
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package app.revanced.util.patch
|
||||||
|
|
||||||
|
import app.revanced.extensions.findMutableMethodOf
|
||||||
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.Method
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
|
||||||
|
internal abstract class AbstractTransformInstructionsPatch<T> : BytecodePatch() {
|
||||||
|
|
||||||
|
abstract fun filterMap(
|
||||||
|
classDef: ClassDef,
|
||||||
|
method: Method,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
): T?
|
||||||
|
|
||||||
|
abstract fun transform(mutableMethod: MutableMethod, entry: T)
|
||||||
|
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
// Find all instructions
|
||||||
|
buildMap {
|
||||||
|
context.classes.forEach { classDef ->
|
||||||
|
classDef.methods.let { methods ->
|
||||||
|
buildMap methodList@{
|
||||||
|
methods.forEach methods@{ method ->
|
||||||
|
with(method.implementation?.instructions ?: return@methods) {
|
||||||
|
ArrayDeque<T>().also { patchIndices ->
|
||||||
|
this.forEachIndexed { index, instruction ->
|
||||||
|
val result = filterMap(classDef, method, instruction, index)
|
||||||
|
if (result != null) {
|
||||||
|
patchIndices.add(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also { if (it.isEmpty()) return@methods }.let { patches ->
|
||||||
|
put(method, patches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also { if (it.isEmpty()) return@forEach }.let { methodPatches ->
|
||||||
|
put(classDef, methodPatches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.forEach { (classDef, methods) ->
|
||||||
|
// And finally transform the instructions...
|
||||||
|
with(context.proxy(classDef).mutableClass) {
|
||||||
|
methods.forEach { (method, patches) ->
|
||||||
|
val mutableMethod = findMutableMethodOf(method)
|
||||||
|
while (!patches.isEmpty()) {
|
||||||
|
transform(mutableMethod, patches.removeLast())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
92
src/main/kotlin/app/revanced/util/patch/MethodCall.kt
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package app.revanced.util.patch
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.replaceInstruction
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.ClassDef
|
||||||
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
|
||||||
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
|
internal typealias Instruction35cInfo = Triple<IMethodCall, Instruction35c, Int>
|
||||||
|
|
||||||
|
internal interface IMethodCall {
|
||||||
|
val definedClassName: String
|
||||||
|
val methodName: String
|
||||||
|
val methodParams: Array<String>
|
||||||
|
val returnType: String
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces an invoke-virtual instruction with an invoke-static instruction,
|
||||||
|
* which calls a static replacement method in the respective integrations class.
|
||||||
|
* The method definition in the integrations class is expected to be the same,
|
||||||
|
* except that the method should be static and take as a first parameter
|
||||||
|
* an instance of the class, in which the original method was defined in.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* original method: Window#setFlags(int, int)
|
||||||
|
*
|
||||||
|
* replacement method: Integrations#setFlags(Window, int, int)
|
||||||
|
*/
|
||||||
|
fun replaceInvokeVirtualWithIntegrations(
|
||||||
|
definingClassDescriptor: String,
|
||||||
|
method: MutableMethod,
|
||||||
|
instruction: Instruction35c,
|
||||||
|
instructionIndex: Int
|
||||||
|
) {
|
||||||
|
val registers = arrayOf(
|
||||||
|
instruction.registerC,
|
||||||
|
instruction.registerD,
|
||||||
|
instruction.registerE,
|
||||||
|
instruction.registerF,
|
||||||
|
instruction.registerG
|
||||||
|
)
|
||||||
|
val argsNum = methodParams.size + 1 // + 1 for instance of definedClassName
|
||||||
|
if (argsNum > registers.size) {
|
||||||
|
// should never happen, but just to be sure (also for the future) a safety check
|
||||||
|
throw RuntimeException(
|
||||||
|
"Not enough registers for ${definedClassName}#${methodName}: " +
|
||||||
|
"Required $argsNum registers, but only got ${registers.size}."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val args = registers.take(argsNum).joinToString(separator = ", ") { reg -> "v${reg}" }
|
||||||
|
val replacementMethodDefinition =
|
||||||
|
"${methodName}(${definedClassName}${methodParams.joinToString(separator = "")})${returnType}"
|
||||||
|
|
||||||
|
method.replaceInstruction(
|
||||||
|
instructionIndex,
|
||||||
|
"invoke-static { $args }, ${definingClassDescriptor}->${replacementMethodDefinition}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified E> fromMethodReference(methodReference: MethodReference)
|
||||||
|
where E : Enum<E>, E : IMethodCall = enumValues<E>().firstOrNull { search ->
|
||||||
|
search.definedClassName == methodReference.definingClass
|
||||||
|
&& search.methodName == methodReference.name
|
||||||
|
&& methodReference.parameterTypes.toTypedArray().contentEquals(search.methodParams)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal inline fun <reified E> filterMapInstruction35c(
|
||||||
|
integrationsClassDescriptorPrefix: String,
|
||||||
|
classDef: ClassDef,
|
||||||
|
instruction: Instruction,
|
||||||
|
instructionIndex: Int
|
||||||
|
): Instruction35cInfo? where E : Enum<E>, E : IMethodCall {
|
||||||
|
if (classDef.type.startsWith(integrationsClassDescriptorPrefix)) {
|
||||||
|
// avoid infinite recursion
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val invokeInstruction = instruction as Instruction35c
|
||||||
|
val methodRef = invokeInstruction.reference as MethodReference
|
||||||
|
val methodCall = fromMethodReference<E>(methodRef) ?: return null
|
||||||
|
|
||||||
|
return Instruction35cInfo(methodCall, invokeInstruction, instructionIndex)
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 5.0 KiB |