Compare commits

...

10 Commits

Author SHA1 Message Date
semantic-release-bot
e67d27c4b0 chore(release): 2.159.0-dev.2 [skip ci]
# [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)) ([2223b07](2223b07dbe))
2023-02-01 19:54:19 +00:00
Linus
2223b07dbe feat: spoof-wifi-connection patch (#1527)
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Linus789 <Linus789@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-01 20:52:41 +01:00
semantic-release-bot
4e3c06684a chore(release): 2.159.0-dev.1 [skip ci]
# [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)) ([aefc1f0](aefc1f02a4))

### Features

* **music:** bump patches compatibility to v5.41.50 ([#1551](https://github.com/revanced/revanced-patches/issues/1551)) ([17b046d](17b046df60))
* **spotify-lite:** enable on-demand patch ([8d57c55](8d57c555a0))
2023-02-01 19:29:44 +00:00
LisoUseInAIKyrios
aefc1f02a4 fix(youtube/custom-branding): correct scaling, margin and images (#1580) 2023-02-01 20:26:32 +01:00
EvadeMaster
762e290658 chore(youtube): word patch descriptions clearly (#1571)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-01 20:24:23 +01:00
EvadeMaster
17b046df60 feat(music): bump patches compatibility to v5.41.50 (#1551)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2023-02-01 20:24:12 +01:00
illerokcob
8d57c555a0 feat(spotify-lite): enable on-demand patch 2023-01-30 01:56:12 +01:00
semantic-release-bot
8e4235af16 chore(release): 2.158.0 [skip ci]
# [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 ([d3bd5f6](d3bd5f65ef))
* **youtube:** resolve duplicate preference keys ([#1550](https://github.com/revanced/revanced-patches/issues/1550)) ([5324d47](5324d471c9))

### Features

* **irplus:** `remove-ads` patch ([#1554](https://github.com/revanced/revanced-patches/issues/1554)) ([86e28ac](86e28acd2f))
2023-01-29 10:01:44 +00:00
oSumAtrIX
b3f9858402 chore: merge branch dev to main (#1559) 2023-01-29 10:59:48 +01:00
github-actions[bot]
bd9c89cdcc chore: merge branch dev to main (#1553)
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: illerokcob <113302047+illerokcob@users.noreply.github.com>
2023-01-28 20:07:06 +01:00
43 changed files with 532 additions and 100 deletions

View File

@@ -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)

View File

@@ -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>

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 2.158.0-dev.1 version = 2.159.0-dev.2

File diff suppressed because one or more lines are too long

View File

@@ -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)
}
}

View File

@@ -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()
} }
} }

View File

@@ -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(

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -22,9 +22,10 @@ import app.revanced.patcher.annotation.Package
"5.31.50", "5.31.50",
"5.34.51", "5.34.51",
"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"
) )
)] )]
) )

View File

@@ -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"
) )
)] )]
) )

View File

@@ -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

View File

@@ -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
)
)

View File

@@ -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()
}
}

View File

@@ -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(

View File

@@ -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(

View File

@@ -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()
}
}

View 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)
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB