chore: merge branch dev to main (#2421)

This commit is contained in:
oSumAtrIX 2023-06-22 01:29:50 +02:00 committed by GitHub
commit 29b7d26f9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
69 changed files with 931 additions and 888 deletions

View file

@ -1,3 +1,80 @@
# [2.178.0-dev.9](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.8...v2.178.0-dev.9) (2023-06-21)
### Features
* **twitch:** 15.4.1 support ([#2462](https://github.com/revanced/revanced-patches/issues/2462)) ([826ed49](https://github.com/revanced/revanced-patches/commit/826ed49c7ca5a00e383b743f88f75dbfc00adb43))
# [2.178.0-dev.8](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.7...v2.178.0-dev.8) (2023-06-20)
### Bug Fixes
* **boostforreddit:** use correct options ([ec39732](https://github.com/revanced/revanced-patches/commit/ec39732a05f7c4c3360b8ba42fe50fd60952e6ac))
# [2.178.0-dev.7](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.6...v2.178.0-dev.7) (2023-06-19)
### Features
* **youtube-music:** remove version compatibility constraints ([276af14](https://github.com/revanced/revanced-patches/commit/276af1415a4d354c62fe6259b6559bca1fa84f08))
# [2.178.0-dev.6](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.5...v2.178.0-dev.6) (2023-06-18)
### Bug Fixes
* **youtube/hide-album-cards:** call correct integrations method ([0dbffaa](https://github.com/revanced/revanced-patches/commit/0dbffaae7d6dcb7050a9ea6e3c771839bcfdfbe1))
# [2.178.0-dev.5](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.4...v2.178.0-dev.5) (2023-06-18)
### Features
* **youtube/hide-layout-components:** separate hiding expandable chips and chapters ([3fb1ce9](https://github.com/revanced/revanced-patches/commit/3fb1ce9f9af150b784e42aaf5b419bb123c08375))
# [2.178.0-dev.4](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.3...v2.178.0-dev.4) (2023-06-18)
### Features
* **boostforreddit:** add `change-oauth-client-id` patch ([3dbc4bd](https://github.com/revanced/revanced-patches/commit/3dbc4bd49df1656893ef69c68550a2deb6a92cb7))
# [2.178.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.2...v2.178.0-dev.3) (2023-06-17)
### Bug Fixes
* **youtube/comments:** add missing filter ([#2423](https://github.com/revanced/revanced-patches/issues/2423)) ([cab04b3](https://github.com/revanced/revanced-patches/commit/cab04b3a56cfc5bf00b7c6fcf6f86ab75aa5d4fd))
# [2.178.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.178.0-dev.1...v2.178.0-dev.2) (2023-06-16)
### Bug Fixes
* **googlerecorder/remove-device-restrictions:** add missing app constraint ([#2438](https://github.com/revanced/revanced-patches/issues/2438)) ([d5efe26](https://github.com/revanced/revanced-patches/commit/d5efe26f8959cde75dd3865ec3c2df4b05210e4a))
# [2.178.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.177.1-dev.2...v2.178.0-dev.1) (2023-06-16)
### Features
* **google-recorder:** add `remove-device-restrictions` patch ([ef96ed1](https://github.com/revanced/revanced-patches/commit/ef96ed124e12091dde34124eabd8be9f2bb9280c))
## [2.177.1-dev.2](https://github.com/revanced/revanced-patches/compare/v2.177.1-dev.1...v2.177.1-dev.2) (2023-06-14)
### Bug Fixes
* **youtube:** separate `hide-ads` to `hide-layout-components` patch ([7e0417f](https://github.com/revanced/revanced-patches/commit/7e0417f6728fa7b79a9d8cbcfd3ccba484a5567d))
## [2.177.1-dev.1](https://github.com/revanced/revanced-patches/compare/v2.177.0...v2.177.1-dev.1) (2023-06-14)
### Bug Fixes
* don't include all Litho patches, when not included ([fc69491](https://github.com/revanced/revanced-patches/commit/fc69491dfe4b119d46dd3da27b556e55fe0cecfb))
# [2.177.0](https://github.com/revanced/revanced-patches/compare/v2.176.1...v2.177.0) (2023-06-12) # [2.177.0](https://github.com/revanced/revanced-patches/compare/v2.176.1...v2.177.0) (2023-06-12)

115
README.md
View file

@ -25,7 +25,6 @@ The official ReVanced Patches.
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.19.35 | | `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.19.35 |
| `hide-ads` | Removes general ads. | 18.19.35 | | `hide-ads` | Removes general ads. | 18.19.35 |
| `hide-album-cards` | Hides the album cards below the artist description. | 18.19.35 | | `hide-album-cards` | Hides the album cards below the artist description. | 18.19.35 |
| `hide-artist-card` | Hides the artist card below the searchbar. | 18.19.35 |
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.19.35 | | `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.19.35 |
| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.19.35 | | `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.19.35 |
| `hide-captions-button` | Hides the captions button on video player. | 18.19.35 | | `hide-captions-button` | Hides the captions button on video player. | 18.19.35 |
@ -36,6 +35,7 @@ The official ReVanced Patches.
| `hide-filter-bar` | Hides the filter bar in video feeds. | 18.19.35 | | `hide-filter-bar` | Hides the filter bar in video feeds. | 18.19.35 |
| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.19.35 | | `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.19.35 |
| `hide-info-cards` | Hides info cards in videos. | 18.19.35 | | `hide-info-cards` | Hides info cards in videos. | 18.19.35 |
| `hide-layout-components` | Hides general layout components. | 18.19.35 |
| `hide-load-more-button` | Hides the button under videos that loads similar videos. | 18.19.35 | | `hide-load-more-button` | Hides the button under videos that loads similar videos. | 18.19.35 |
| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | 18.19.35 | | `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | 18.19.35 |
| `hide-player-overlay` | Hides the dark background overlay from the player when player controls are visible. | all | | `hide-player-overlay` | Hides the dark background overlay from the player when player controls are visible. | all |
@ -71,16 +71,15 @@ The official ReVanced Patches.
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `background-play` | Enables playing music in the background. | all | | `background-play` | Enables playing music in the background. | all |
| `bypass-certificate-checks` | Bypasses certificate checks which prevent YouTube Music from working on Android Auto. | 5.39.52 | | `bypass-certificate-checks` | Bypasses certificate checks which prevent YouTube Music from working on Android Auto. | all |
| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | all | | `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | all |
| `compact-header` | Hides the music category bar at the top of the homepage. | all | | `compact-header` | Hides the music category bar at the top of the homepage. | all |
| `exclusive-audio-playback` | Enables the option to play music without video. | all | | `exclusive-audio-playback` | Enables the option to play music without video. | all |
| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.39.52 | | `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | all |
| `minimized-playback-music` | Enables minimized playback on Kids music. | all | | `minimized-playback-music` | Enables minimized playback on Kids music. | all |
| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | all |
| `music-video-ads` | Removes ads in the music player. | all | | `music-video-ads` | Removes ads in the music player. | all |
| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | all |
| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | all | | `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | all |
| `vanced-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | all |
</details> </details>
### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill) ### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill)
@ -120,13 +119,13 @@ The official ReVanced Patches.
| 💊 Patch | 📜 Description | 🏹 Target Version | | 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:| |:--------:|:--------------:|:-----------------:|
| `auto-claim-channel-points` | Automatically claim Channel Points. | all | | `auto-claim-channel-points` | Automatically claim Channel Points. | 15.4.1 |
| `block-audio-ads` | Blocks audio ads in streams and VODs. | 14.6.1 | | `block-audio-ads` | Blocks audio ads in streams and VODs. | 15.4.1 |
| `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 14.6.1 | | `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 15.4.1 |
| `block-video-ads` | Blocks video ads in streams and VODs. | 14.6.1 | | `block-video-ads` | Blocks video ads in streams and VODs. | 15.4.1 |
| `debug-mode` | Enables Twitch's internal debugging mode. | all | | `debug-mode` | Enables Twitch's internal debugging mode. | all |
| `settings` | Adds settings menu to Twitch. | all | | `settings` | Adds settings menu to Twitch. | all |
| `show-deleted-messages` | Shows deleted chat messages behind a clickable spoiler. | all | | `show-deleted-messages` | Shows deleted chat messages behind a clickable spoiler. | 15.4.1 |
</details> </details>
### [📦 `com.twitter.android`](https://play.google.com/store/apps/details?id=com.twitter.android) ### [📦 `com.twitter.android`](https://play.google.com/store/apps/details?id=com.twitter.android)
@ -205,6 +204,14 @@ The official ReVanced Patches.
| `spoof-signature` | Spoofs the signature of the app. | all | | `spoof-signature` | Spoofs the signature of the app. | all |
</details> </details>
### [📦 `com.rubenmayayo.reddit`](https://play.google.com/store/apps/details?id=com.rubenmayayo.reddit)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `change-oauth-client-id` | Changes the OAuth client ID in Boost for Reddit. | all |
</details>
### [📦 `com.laurencedawson.reddit_sync.pro`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync.pro) ### [📦 `com.laurencedawson.reddit_sync.pro`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync.pro)
<details> <details>
@ -293,6 +300,14 @@ The official ReVanced Patches.
| `remove-debugging-detection` | Removes the USB and wireless debugging checks. | all | | `remove-debugging-detection` | Removes the USB and wireless debugging checks. | all |
</details> </details>
### [📦 `com.google.android.apps.recorder`](https://play.google.com/store/apps/details?id=com.google.android.apps.recorder)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `remove-device-restrictions` | Removes restrictions from using the app on any device. | all |
</details>
### [📦 `com.dci.dev.androidtwelvewidgets`](https://play.google.com/store/apps/details?id=com.dci.dev.androidtwelvewidgets) ### [📦 `com.dci.dev.androidtwelvewidgets`](https://play.google.com/store/apps/details?id=com.dci.dev.androidtwelvewidgets)
<details> <details>
@ -325,6 +340,30 @@ The official ReVanced Patches.
| `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all | | `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all |
</details> </details>
### [📦 `tv.trakt.trakt`](https://play.google.com/store/apps/details?id=tv.trakt.trakt)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | 4.6377 |
</details>
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `com.vsco.cam`](https://play.google.com/store/apps/details?id=com.vsco.cam) ### [📦 `com.vsco.cam`](https://play.google.com/store/apps/details?id=com.vsco.cam)
<details> <details>
@ -341,22 +380,6 @@ The official ReVanced Patches.
| `unlock-pro` | Unlocks all pro features. | all | | `unlock-pro` | Unlocks all pro features. | all |
</details> </details>
### [📦 `com.candylink.openvpn`](https://play.google.com/store/apps/details?id=com.candylink.openvpn)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks premium features. | all |
</details>
### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio) ### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio)
<details> <details>
@ -365,22 +388,6 @@ The official ReVanced Patches.
| `unlock-pro` | Unlocks all pro features. | all | | `unlock-pro` | Unlocks all pro features. | all |
</details> </details>
### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | 4.6377 |
</details>
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses) ### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses)
<details> <details>
@ -389,14 +396,6 @@ The official ReVanced Patches.
| `unlock-pro` | Unlocks all professional features. | 3.4.9 | | `unlock-pro` | Unlocks all professional features. | 3.4.9 |
</details> </details>
### [📦 `tv.trakt.trakt`](https://play.google.com/store/apps/details?id=tv.trakt.trakt)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks pro features. | all |
</details>
### [📦 `com.wakdev.apps.nfctools.se`](https://play.google.com/store/apps/details?id=com.wakdev.apps.nfctools.se) ### [📦 `com.wakdev.apps.nfctools.se`](https://play.google.com/store/apps/details?id=com.wakdev.apps.nfctools.se)
<details> <details>
@ -405,6 +404,22 @@ The official ReVanced Patches.
| `unlock-pro` | Unlocks all pro features. | all | | `unlock-pro` | Unlocks all pro features. | all |
</details> </details>
### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks all pro features. | all |
</details>
### [📦 `com.candylink.openvpn`](https://play.google.com/store/apps/details?id=com.candylink.openvpn)
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `unlock-pro` | Unlocks premium features. | all |
</details>
### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task) ### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task)
<details> <details>

View file

@ -1,2 +1,2 @@
kotlin.code.style = official kotlin.code.style = official
version = 2.177.0 version = 2.178.0-dev.9

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
package app.revanced.patches.googlerecorder.restrictions.fingereprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object OnApplicationCreateFingerprint : MethodFingerprint(
strings = listOf("com.google.android.feature.PIXEL_2017_EXPERIENCE"),
customFingerprint = custom@{ methodDef, classDef ->
if (methodDef.name != "onCreate") return@custom false
classDef.type.endsWith("RecorderApplication;")
}
)

View file

@ -0,0 +1,45 @@
package app.revanced.patches.googlerecorder.restrictions.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Package
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
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.googlerecorder.restrictions.fingereprints.OnApplicationCreateFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("remove-device-restrictions")
@Description("Removes restrictions from using the app on any device.")
@Compatibility([Package("com.google.android.apps.recorder")])
@Version("0.0.1")
class RemoveDeviceRestrictions : BytecodePatch(
listOf(OnApplicationCreateFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
OnApplicationCreateFingerprint.result?.let {
val featureStringIndex = it.scanResult.stringsScanResult!!.matches.first().index
it.mutableMethod.apply {
// Remove check for device restrictions.
removeInstructions(featureStringIndex - 2, 5)
val featureAvailableRegister = getInstruction<OneRegisterInstruction>(featureStringIndex).registerA
// Override "isPixelDevice()" to return true.
addInstruction(featureStringIndex, "const/4 v$featureAvailableRegister, 0x1")
}
} ?: return OnApplicationCreateFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View file

@ -10,19 +10,17 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint
import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint
import app.revanced.patches.music.annotations.MusicCompatibility
@Patch @Patch
@Name("music-video-ads") @Name("music-video-ads")
@Description("Removes ads in the music player.") @Description("Removes ads in the music player.")
@MusicVideoAdsCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class MusicVideoAdsPatch : BytecodePatch( class MusicVideoAdsPatch : BytecodePatch(
listOf( listOf(ShowMusicVideoAdsConstructorFingerprint)
ShowMusicVideoAdsConstructorFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef) ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef)

View file

@ -1,8 +1,8 @@
package app.revanced.patches.music.ad.video.annotations package app.revanced.patches.music.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")]) @Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class MusicVideoAdsCompatibility internal annotation class MusicCompatibility

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.audio.codecs.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class CodecsUnlockCompatibility

View file

@ -10,7 +10,7 @@ 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.annotations.Patch
import app.revanced.patcher.util.smali.toInstruction import app.revanced.patcher.util.smali.toInstruction
import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.audio.codecs.fingerprints.AllCodecsReferenceFingerprint import app.revanced.patches.music.audio.codecs.fingerprints.AllCodecsReferenceFingerprint
import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprint import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprint
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -18,7 +18,7 @@ import org.jf.dexlib2.Opcode
@Patch @Patch
@Name("codecs-unlock") @Name("codecs-unlock")
@Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.") @Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.")
@CodecsUnlockCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class CodecsUnlockPatch : BytecodePatch( class CodecsUnlockPatch : BytecodePatch(
listOf( listOf(

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.audio.exclusiveaudio.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class ExclusiveAudioCompatibility

View file

@ -10,18 +10,16 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AudioOnlyEnablerFingerprint import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AudioOnlyEnablerFingerprint
@Patch @Patch
@Name("exclusive-audio-playback") @Name("exclusive-audio-playback")
@Description("Enables the option to play music without video.") @Description("Enables the option to play music without video.")
@ExclusiveAudioCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class ExclusiveAudioPatch : BytecodePatch( class ExclusiveAudioPatch : BytecodePatch(
listOf( listOf(AudioOnlyEnablerFingerprint)
AudioOnlyEnablerFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val method = AudioOnlyEnablerFingerprint.result!!.mutableMethod val method = AudioOnlyEnablerFingerprint.result!!.mutableMethod

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.layout.compactheader.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class CompactHeaderCompatibility

View file

@ -9,19 +9,17 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.layout.compactheader.annotations.CompactHeaderCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint
import org.jf.dexlib2.builder.instruction.BuilderInstruction11x import org.jf.dexlib2.builder.instruction.BuilderInstruction11x
@Patch(false) @Patch(false)
@Name("compact-header") @Name("compact-header")
@Description("Hides the music category bar at the top of the homepage.") @Description("Hides the music category bar at the top of the homepage.")
@CompactHeaderCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class CompactHeaderPatch : BytecodePatch( class CompactHeaderPatch : BytecodePatch(
listOf( listOf(CompactHeaderConstructorFingerprint)
CompactHeaderConstructorFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = CompactHeaderConstructorFingerprint.result!! val result = CompactHeaderConstructorFingerprint.result!!

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.layout.minimizedplayback.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class MinimizedPlaybackCompatibility

View file

@ -9,18 +9,16 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
@Patch @Patch
@Name("minimized-playback-music") @Name("minimized-playback-music")
@Description("Enables minimized playback on Kids music.") @Description("Enables minimized playback on Kids music.")
@MinimizedPlaybackCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class MinimizedPlaybackPatch : BytecodePatch( class MinimizedPlaybackPatch : BytecodePatch(
listOf( listOf(MinimizedPlaybackManagerFingerprint)
MinimizedPlaybackManagerFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstruction( MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstruction(

View file

@ -1,31 +0,0 @@
package app.revanced.patches.music.layout.premium.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52"
)
)]
)
@Target(AnnotationTarget.CLASS)
internal annotation class HideGetPremiumCompatibility

View file

@ -11,19 +11,17 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.layout.premium.annotations.HideGetPremiumCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint
import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint
@Patch @Patch
@Name("hide-get-premium") @Name("hide-get-premium")
@Description("Removes all \"Get Premium\" evidences from the avatar menu.") @Description("Removes all \"Get Premium\" evidences from the avatar menu.")
@HideGetPremiumCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideGetPremiumPatch : BytecodePatch( class HideGetPremiumPatch : BytecodePatch(
listOf( listOf(HideGetPremiumParentFingerprint)
HideGetPremiumParentFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val parentResult = HideGetPremiumParentFingerprint.result!! val parentResult = HideGetPremiumParentFingerprint.result!!
@ -33,9 +31,10 @@ class HideGetPremiumPatch : BytecodePatch(
val parentMethod = parentResult.mutableMethod val parentMethod = parentResult.mutableMethod
parentMethod.replaceInstruction( parentMethod.replaceInstruction(
startIndex, """ startIndex,
const/4 v1, 0x0 """
""" const/4 v1, 0x0
"""
) )
val result = HideGetPremiumFingerprint.result!! val result = HideGetPremiumFingerprint.result!!

View file

@ -1,13 +0,0 @@
package app.revanced.patches.music.layout.tastebuilder.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
/**
* -- Note 2022-08-05 --
* Since 5.17.xx the tastebuilder component is dismissible, so this patch is less useful
* also it is partly litho now
*/
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class RemoveTasteBuilderCompatibility

View file

@ -1,34 +0,0 @@
package app.revanced.patches.music.layout.tastebuilder.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object TasteBuilderConstructorFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf(
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.CONST
)
)

View file

@ -1,42 +0,0 @@
package app.revanced.patches.music.layout.tastebuilder.patch
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.InstructionExtensions.addInstructions
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.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility
import app.revanced.patches.music.layout.tastebuilder.fingerprints.TasteBuilderConstructorFingerprint
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
@Patch
@Name("tasteBuilder-remover")
@Description("Removes the \"Tell us which artists you like\" card from the home screen.")
@RemoveTasteBuilderCompatibility
@Version("0.0.1")
class RemoveTasteBuilderPatch : BytecodePatch(
listOf(
TasteBuilderConstructorFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = TasteBuilderConstructorFingerprint.result!!
val method = result.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex - 8
val register = (method.implementation!!.instructions[insertIndex] as Instruction22c).registerA
method.addInstructions(
insertIndex,
"""
const/16 v1, 0x8
invoke-virtual {v${register}, v1}, Landroid/view/View;->setVisibility(I)V
"""
)
return PatchResultSuccess()
}
}

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.layout.upgradebutton.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class RemoveUpgradeButtonCompatibility

View file

@ -10,7 +10,7 @@ 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.annotations.Patch
import app.revanced.patcher.util.smali.toInstructions import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction22t import org.jf.dexlib2.builder.instruction.BuilderInstruction22t
@ -21,12 +21,10 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch @Patch
@Name("upgrade-button-remover") @Name("upgrade-button-remover")
@Description("Removes the upgrade tab from the pivot bar.") @Description("Removes the upgrade tab from the pivot bar.")
@RemoveUpgradeButtonCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class RemoveUpgradeButtonPatch : BytecodePatch( class RemoveUpgradeButtonPatch : BytecodePatch(
listOf( listOf(PivotBarConstructorFingerprint)
PivotBarConstructorFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = PivotBarConstructorFingerprint.result!! val result = PivotBarConstructorFingerprint.result!!

View file

@ -1,35 +0,0 @@
package app.revanced.patches.music.misc.androidauto.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.apps.youtube.music",
arrayOf(
"5.14.53",
"5.16.51",
"5.17.51",
"5.21.52",
"5.22.54",
"5.23.50",
"5.25.51",
"5.25.52",
"5.26.52",
"5.27.51",
"5.28.52",
"5.29.52",
"5.31.50",
"5.34.51",
"5.36.51",
"5.38.53",
"5.39.52",
"5.40.51",
"5.41.50",
"5.48.52"
)
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class BypassCertificateChecksCompatibility

View file

@ -11,18 +11,16 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.misc.androidauto.annotations.BypassCertificateChecksCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.misc.androidauto.fingerprints.CheckCertificateFingerprint import app.revanced.patches.music.misc.androidauto.fingerprints.CheckCertificateFingerprint
@Patch @Patch
@Name("bypass-certificate-checks") @Name("bypass-certificate-checks")
@Description("Bypasses certificate checks which prevent YouTube Music from working on Android Auto.") @Description("Bypasses certificate checks which prevent YouTube Music from working on Android Auto.")
@BypassCertificateChecksCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class BypassCertificateChecksPatch : BytecodePatch( class BypassCertificateChecksPatch : BytecodePatch(
listOf( listOf(CheckCertificateFingerprint)
CheckCertificateFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
CheckCertificateFingerprint.result?.let { result -> CheckCertificateFingerprint.result?.let { result ->

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.misc.microg.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class MusicMicroGPatchCompatibility

View file

@ -1,65 +1,65 @@
package app.revanced.patches.music.misc.microg.patch.bytecode package app.revanced.patches.music.misc.microg.patch.bytecode
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.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.misc.microg.fingerprints.* import app.revanced.patches.music.misc.microg.fingerprints.*
import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch import app.revanced.patches.music.misc.microg.patch.resource.MicroGResourcePatch
import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
import app.revanced.patches.youtube.misc.microg.shared.Constants import app.revanced.patches.youtube.misc.microg.shared.Constants
import app.revanced.util.microg.MicroGBytecodeHelper import app.revanced.util.microg.MicroGBytecodeHelper
@Patch @Patch
@DependsOn([MusicMicroGResourcePatch::class]) @DependsOn([MicroGResourcePatch::class])
@Name("music-microg-support") @Name("vanced-microg-support")
@Description("Allows YouTube Music ReVanced to run without root and under a different package name.") @Description("Allows YouTube Music ReVanced to run without root and under a different package name.")
@MusicMicroGPatchCompatibility @MusicCompatibility
@Version("0.0.2") @Version("0.0.2")
class MusicMicroGBytecodePatch : BytecodePatch( class MicroGBytecodePatch : BytecodePatch(
listOf( listOf(
ServiceCheckFingerprint, ServiceCheckFingerprint,
GooglePlayUtilityFingerprint, GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint, CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint, CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint, CastContextFetchFingerprint,
PrimeFingerprint, PrimeFingerprint,
) )
) { ) {
// NOTE: the previous patch also replaced the following strings, but it seems like they are not needed: // NOTE: the previous patch also replaced the following strings, but it seems like they are not needed:
// - "com.google.android.gms.chimera.GmsIntentOperationService", // - "com.google.android.gms.chimera.GmsIntentOperationService",
// - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks", // - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks",
// - "com.google.android.gms.phenotype.internal.IPhenotypeService", // - "com.google.android.gms.phenotype.internal.IPhenotypeService",
// - "com.google.android.gms.phenotype.PACKAGE_NAME", // - "com.google.android.gms.phenotype.PACKAGE_NAME",
// - "com.google.android.gms.phenotype.UPDATE", // - "com.google.android.gms.phenotype.UPDATE",
// - "com.google.android.gms.phenotype", // - "com.google.android.gms.phenotype",
override fun execute(context: BytecodeContext) = override fun execute(context: BytecodeContext) =
// apply common microG patch // apply common microG patch
MicroGBytecodeHelper.patchBytecode( MicroGBytecodeHelper.patchBytecode(
context, context,
arrayOf( arrayOf(
MicroGBytecodeHelper.packageNameTransform( MicroGBytecodeHelper.packageNameTransform(
Constants.PACKAGE_NAME, Constants.PACKAGE_NAME,
Constants.REVANCED_PACKAGE_NAME Constants.REVANCED_PACKAGE_NAME
) )
), ),
MicroGBytecodeHelper.PrimeMethodTransformationData( MicroGBytecodeHelper.PrimeMethodTransformationData(
PrimeFingerprint, PrimeFingerprint,
MUSIC_PACKAGE_NAME, MUSIC_PACKAGE_NAME,
REVANCED_MUSIC_PACKAGE_NAME REVANCED_MUSIC_PACKAGE_NAME
), ),
listOf( listOf(
ServiceCheckFingerprint, ServiceCheckFingerprint,
GooglePlayUtilityFingerprint, GooglePlayUtilityFingerprint,
CastDynamiteModuleFingerprint, CastDynamiteModuleFingerprint,
CastDynamiteModuleV2Fingerprint, CastDynamiteModuleV2Fingerprint,
CastContextFetchFingerprint CastContextFetchFingerprint
) )
).let { PatchResultSuccess() } ).let { PatchResultSuccess() }
} }

View file

@ -7,7 +7,7 @@ import app.revanced.patcher.data.ResourceContext
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.ResourcePatch import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME
import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME
@ -16,11 +16,11 @@ import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_PACKAGE_S
import app.revanced.util.microg.MicroGManifestHelper import app.revanced.util.microg.MicroGManifestHelper
import app.revanced.util.microg.MicroGResourceHelper import app.revanced.util.microg.MicroGResourceHelper
@Name("music-microg-resource-patch") @Name("microg-resource-patch")
@Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.") @Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.")
@MusicMicroGPatchCompatibility @MusicCompatibility
@Version("0.0.2") @Version("0.0.2")
class MusicMicroGResourcePatch : ResourcePatch { class MicroGResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult { override fun execute(context: ResourceContext): PatchResult {
// update manifest // update manifest
MicroGResourceHelper.patchManifest( MicroGResourceHelper.patchManifest(

View file

@ -1,8 +0,0 @@
package app.revanced.patches.music.premium.backgroundplay.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.apps.youtube.music")])
@Target(AnnotationTarget.CLASS)
internal annotation class BackgroundPlayCompatibility

View file

@ -9,18 +9,16 @@ import app.revanced.patcher.patch.BytecodePatch
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.annotations.Patch
import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility import app.revanced.patches.music.annotations.MusicCompatibility
import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint
@Patch @Patch
@Name("background-play") @Name("background-play")
@Description("Enables playing music in the background.") @Description("Enables playing music in the background.")
@BackgroundPlayCompatibility @MusicCompatibility
@Version("0.0.1") @Version("0.0.1")
class BackgroundPlayPatch : BytecodePatch( class BackgroundPlayPatch : BytecodePatch(
listOf( listOf(BackgroundPlaybackDisableFingerprint)
BackgroundPlaybackDisableFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
BackgroundPlaybackDisableFingerprint.result!!.mutableMethod.addInstructions( BackgroundPlaybackDisableFingerprint.result!!.mutableMethod.addInstructions(

View file

@ -0,0 +1,56 @@
package app.revanced.patches.reddit.customclients
import android.os.Environment
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.patch.*
import java.io.File
abstract class AbstractChangeOAuthClientIdPatch(
private val redirectUri: String,
private val options: ChangeOAuthClientIdOptionsContainer,
private val fingerprint: MethodFingerprint,
) : BytecodePatch(listOf(fingerprint)) {
override fun execute(context: BytecodeContext): PatchResult {
if (options.clientId == null) {
// Test if on Android
try {
Class.forName("android.os.Environment")
} catch (e: ClassNotFoundException) {
return PatchResultError("No client ID provided")
}
File(Environment.getExternalStorageDirectory(), "reddit_client_id_revanced.txt").also {
if (it.exists()) return@also
val error = """
In order to use this patch, you need to provide a client ID.
You can do this by creating a file at ${it.absolutePath} with the client ID as its content.
Alternatively, you can provide the client ID using patch options.
You can get your client ID from https://www.reddit.com/prefs/apps.
The application type has to be "Installed app" and the redirect URI has to be set to "$redirectUri".
""".trimIndent()
return PatchResultError(error)
}.let { options.clientId = it.readText().trim() }
}
return fingerprint.patch(context)
}
abstract fun MethodFingerprint.patch(context: BytecodeContext): PatchResult
companion object Options {
open class ChangeOAuthClientIdOptionsContainer : OptionsContainer() {
var clientId by option(
PatchOption.StringOption(
"client-id",
null,
"OAuth client ID",
"The Reddit OAuth client ID."
)
)
}
}
}

View file

@ -0,0 +1,11 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object GetClientIdFingerprint : MethodFingerprint(
customFingerprint = custom@{ methodDef, classDef ->
if (!classDef.type.endsWith("Credentials;")) return@custom false
methodDef.name == "getClientId"
}
)

View file

@ -0,0 +1,37 @@
package app.revanced.patches.reddit.customclients.boostforreddit.api.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.reddit.customclients.AbstractChangeOAuthClientIdPatch
import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.GetClientIdFingerprint
@Patch
@Name("change-oauth-client-id")
@Description("Changes the OAuth client ID in Boost for Reddit.")
@Compatibility([Package("com.rubenmayayo.reddit")])
@Version("0.0.1")
class ChangeOAuthClientIdPatch : AbstractChangeOAuthClientIdPatch(
"http://rubenmayayo.com",
Options,
GetClientIdFingerprint
) {
override fun MethodFingerprint.patch(context: BytecodeContext): PatchResult {
result?.mutableMethod?.addInstructions(
0,
"""
const-string v0, "$clientId"
return-object v0
"""
) ?: return toErrorResult()
return PatchResultSuccess()
}
companion object Options : AbstractChangeOAuthClientIdPatch.Options.ChangeOAuthClientIdOptionsContainer()
}

View file

@ -1,4 +1,4 @@
package app.revanced.patches.syncforreddit.ads.fingerprints package app.revanced.patches.reddit.customclients.syncforreddit.ads.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View file

@ -1,4 +1,4 @@
package app.revanced.patches.syncforreddit.ads.patch package app.revanced.patches.reddit.customclients.syncforreddit.ads.patch
import app.revanced.extensions.toErrorResult import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.* import app.revanced.patcher.annotation.*
@ -9,8 +9,8 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.syncforreddit.ads.fingerprints.IsAdsEnabledFingerprint import app.revanced.patches.reddit.customclients.syncforreddit.ads.fingerprints.IsAdsEnabledFingerprint
import app.revanced.patches.syncforreddit.detection.piracy.patch.DisablePiracyDetectionPatch import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.patch.DisablePiracyDetectionPatch
@Patch @Patch
@Name("disable-ads") @Name("disable-ads")

View file

@ -1,4 +1,4 @@
package app.revanced.patches.syncforreddit.api.fingerprints package app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View file

@ -1,4 +1,4 @@
package app.revanced.patches.syncforreddit.api.fingerprints package app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View file

@ -0,0 +1,68 @@
package app.revanced.patches.reddit.customclients.syncforreddit.api.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.reddit.customclients.AbstractChangeOAuthClientIdPatch
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.GetAuthorizationStringFingerprint
import app.revanced.patches.reddit.customclients.syncforreddit.api.fingerprints.GetBearerTokenFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.StringReference
import java.util.*
@Patch
@Name("change-oauth-client-id")
@Description("Changes the OAuth client ID.")
@Compatibility([Package("com.laurencedawson.reddit_sync"), Package("com.laurencedawson.reddit_sync.pro")])
@Version("0.0.1")
class ChangeOAuthClientIdPatch : AbstractChangeOAuthClientIdPatch(
"http://redditsync/auth",
Options,
GetAuthorizationStringFingerprint,
) {
override fun MethodFingerprint.patch(context: BytecodeContext): PatchResult {
result?.also { result ->
GetBearerTokenFingerprint.also { it.resolve(context, result.classDef) }.result?.mutableMethod?.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
addInstructions(
0,
"""
const-string v0, "Basic $auth"
return-object v0
"""
)
} ?: return GetBearerTokenFingerprint.toErrorResult()
}?.let {
val occurrenceIndex = it.scanResult.stringsScanResult!!.matches.first().index
it.mutableMethod.apply {
val authorizationStringInstruction = getInstruction<ReferenceInstruction>(occurrenceIndex)
val targetRegister = (authorizationStringInstruction as OneRegisterInstruction).registerA
val reference = authorizationStringInstruction.reference as StringReference
val newAuthorizationUrl = reference.string.replace(
"client_id=.*?&".toRegex(),
"client_id=$clientId&"
)
replaceInstruction(
occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\""
)
}
} ?: return toErrorResult()
return PatchResultSuccess()
}
companion object Options : AbstractChangeOAuthClientIdPatch.Options.ChangeOAuthClientIdOptionsContainer()
}

View file

@ -1,4 +1,4 @@
package app.revanced.patches.syncforreddit.detection.piracy.patch package app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.patch
import app.revanced.extensions.toErrorResult import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description

View file

@ -1,101 +0,0 @@
package app.revanced.patches.syncforreddit.api.patch
import android.os.Environment
import app.revanced.patcher.annotation.*
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.*
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.syncforreddit.api.fingerprints.GetAuthorizationStringFingerprint
import app.revanced.patches.syncforreddit.api.fingerprints.GetBearerTokenFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.StringReference
import java.io.File
import java.util.*
@Patch
@Name("change-oauth-client-id")
@Description("Changes the OAuth client ID.")
@Compatibility(
[
Package("com.laurencedawson.reddit_sync"),
Package("com.laurencedawson.reddit_sync.pro")
]
)
@Version("0.0.1")
class ChangeOAuthClientIdPatch : BytecodePatch(
listOf(GetAuthorizationStringFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
if (clientId == null) {
// Test if on Android
try {
Class.forName("android.os.Environment")
} catch (e: ClassNotFoundException) {
return PatchResultError("No client ID provided")
}
File(Environment.getExternalStorageDirectory(), "reddit_client_id_revanced.txt").also {
if (it.exists()) return@also
val error = """
In order to use this patch, you need to provide a client ID.
You can do this by creating a file at ${it.absolutePath} with the client ID as its content.
Alternatively, you can provide the client ID using patch options.
You can get your client ID from https://www.reddit.com/prefs/apps.
The application type has to be "installed app" and the redirect URI has to be set to "http://redditsync/auth"
""".trimIndent()
return PatchResultError(error)
}.let { clientId = it.readText().trim() }
}
GetAuthorizationStringFingerprint.result?.also { result ->
GetBearerTokenFingerprint.also { it.resolve(context, result.classDef) }.result?.mutableMethod?.apply {
val auth = Base64.getEncoder().encodeToString("$clientId:".toByteArray(Charsets.UTF_8))
addInstructions(
0,
"""
const-string v0, "Basic $auth"
return-object v0
"""
)
} ?: return PatchResultError("Could not find required method to patch.")
}?.let {
val occurrenceIndex = it.scanResult.stringsScanResult!!.matches.first().index
it.mutableMethod.apply {
val authorizationStringInstruction = getInstruction<ReferenceInstruction>(occurrenceIndex)
val targetRegister = (authorizationStringInstruction as OneRegisterInstruction).registerA
val reference = authorizationStringInstruction.reference as StringReference
val newAuthorizationUrl = reference.string.replace(
"client_id=.*?&".toRegex(),
"client_id=${clientId!!}&"
)
replaceInstruction(
occurrenceIndex,
"const-string v$targetRegister, \"$newAuthorizationUrl\""
)
}
} ?: return PatchResultError("Could not find required method to patch.")
return PatchResultSuccess()
}
companion object : OptionsContainer() {
var clientId by option(
PatchOption.StringOption(
"client-id",
null,
"OAuth client ID",
"The client ID to use for OAuth."
)
)
}
}

View file

@ -3,20 +3,7 @@ package app.revanced.patches.twitch.ad.audio.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility([Package("tv.twitch.android.app", arrayOf("15.4.1"))])
[
Package(
"tv.twitch.android.app", arrayOf(
"14.3.3",
"14.4.0",
"14.5.0",
"14.5.2",
"14.6.0",
"14.6.1"
)
)
]
)
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class AudioAdsCompatibility internal annotation class AudioAdsCompatibility

View file

@ -3,20 +3,7 @@ package app.revanced.patches.twitch.ad.embedded.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility([Package("tv.twitch.android.app", arrayOf("15.4.1"))])
[
Package(
"tv.twitch.android.app", arrayOf(
"14.3.3",
"14.4.0",
"14.5.0",
"14.5.2",
"14.6.0",
"14.6.1"
)
)
]
)
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class EmbeddedAdsCompatibility internal annotation class EmbeddedAdsCompatibility

View file

@ -3,20 +3,7 @@ package app.revanced.patches.twitch.ad.video.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility( @Compatibility([Package("tv.twitch.android.app", arrayOf("15.4.1"))])
[
Package(
"tv.twitch.android.app", arrayOf(
"14.3.3",
"14.4.0",
"14.5.0",
"14.5.2",
"14.6.0",
"14.6.1"
)
)
]
)
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class VideoAdsCompatibility internal annotation class VideoAdsCompatibility

View file

@ -1,15 +1,12 @@
package app.revanced.patches.twitch.ad.video.fingerprints package app.revanced.patches.twitch.ad.video.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
object CheckAdEligibilityLambdaFingerprint : MethodFingerprint( object CheckAdEligibilityLambdaFingerprint : MethodFingerprint(
"L", returnType = "Lio/reactivex/Single;",
AccessFlags.PRIVATE or AccessFlags.FINAL or AccessFlags.STATIC, parameters = listOf("L"),
listOf("L", "L", "L"),
customFingerprint = { method, _ -> customFingerprint = { method, _ ->
method.definingClass.endsWith("AdEligibilityFetcher;") && method.definingClass.endsWith("/AdEligibilityFetcher;")
method.name.contains("shouldRequestAd") && method.name == "shouldRequestAd"
} }
) )

View file

@ -1,10 +1,11 @@
package app.revanced.patches.twitch.ad.video.fingerprints package app.revanced.patches.twitch.ad.video.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object ContentConfigShowAdsFingerprint : MethodFingerprint( object ContentConfigShowAdsFingerprint : MethodFingerprint(
returnType = "Z",
parameters = listOf(),
customFingerprint = { method, _ -> customFingerprint = { method, _ ->
method.definingClass.endsWith("ContentConfigData;") && method.name == "getShowAds" method.definingClass.endsWith("/ContentConfigData;") && method.name == "getShowAds"
} }
) )

View file

@ -3,6 +3,8 @@ package app.revanced.patches.twitch.ad.video.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object GetReadyToShowAdFingerprint : MethodFingerprint( object GetReadyToShowAdFingerprint : MethodFingerprint(
returnType = "Ltv/twitch/android/core/mvp/presenter/StateAndAction;",
parameters = listOf("L", "L"),
customFingerprint = { method, _ -> customFingerprint = { method, _ ->
method.definingClass.endsWith("/StreamDisplayAdsPresenter;") && method.name == "getReadyToShowAdOrAbort" method.definingClass.endsWith("/StreamDisplayAdsPresenter;") && method.name == "getReadyToShowAdOrAbort"
} }

View file

@ -1,5 +1,6 @@
package app.revanced.patches.twitch.ad.video.patch package app.revanced.patches.twitch.ad.video.patch
import app.revanced.extensions.toErrorResult
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
@ -86,7 +87,7 @@ class VideoAdsPatch : AbstractAdPatch(
) )
// Pretend our player is ineligible for all ads // Pretend our player is ineligible for all ads
with(CheckAdEligibilityLambdaFingerprint.result!!) { CheckAdEligibilityLambdaFingerprint.result?.apply {
mutableMethod.addInstructionsWithLabels( mutableMethod.addInstructionsWithLabels(
0, 0,
""" """
@ -98,9 +99,9 @@ class VideoAdsPatch : AbstractAdPatch(
""", """,
ExternalLabel(skipLabelName, mutableMethod.getInstruction(0)) ExternalLabel(skipLabelName, mutableMethod.getInstruction(0))
) )
} } ?: return CheckAdEligibilityLambdaFingerprint.toErrorResult()
with(GetReadyToShowAdFingerprint.result!!) { GetReadyToShowAdFingerprint.result?.apply {
val adFormatDeclined = "Ltv/twitch/android/shared/display/ads/theatre/StreamDisplayAdsPresenter\$Action\$AdFormatDeclined;" val adFormatDeclined = "Ltv/twitch/android/shared/display/ads/theatre/StreamDisplayAdsPresenter\$Action\$AdFormatDeclined;"
mutableMethod.addInstructionsWithLabels( mutableMethod.addInstructionsWithLabels(
0, 0,
@ -113,10 +114,10 @@ class VideoAdsPatch : AbstractAdPatch(
""", """,
ExternalLabel(skipLabelName, mutableMethod.getInstruction(0)) ExternalLabel(skipLabelName, mutableMethod.getInstruction(0))
) )
} } ?: return GetReadyToShowAdFingerprint.toErrorResult()
// Spoof showAds JSON field // Spoof showAds JSON field
with(ContentConfigShowAdsFingerprint.result!!) { ContentConfigShowAdsFingerprint.result?.apply {
mutableMethod.addInstructions(0, """ mutableMethod.addInstructions(0, """
${createConditionInstructions()} ${createConditionInstructions()}
const/4 v0, 0 const/4 v0, 0
@ -124,7 +125,7 @@ class VideoAdsPatch : AbstractAdPatch(
return v0 return v0
""" """
) )
} } ?: return ContentConfigShowAdsFingerprint.toErrorResult()
SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(
SwitchPreference( SwitchPreference(

View file

@ -3,7 +3,7 @@ package app.revanced.patches.twitch.chat.antidelete.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility([Package("tv.twitch.android.app")]) @Compatibility([Package("tv.twitch.android.app", arrayOf("15.4.1"))])
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class ShowDeletedMessagesCompatibility internal annotation class ShowDeletedMessagesCompatibility

View file

@ -1,5 +1,6 @@
package app.revanced.patches.twitch.chat.antidelete.patch package app.revanced.patches.twitch.chat.antidelete.patch
import app.revanced.extensions.toErrorResult
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
@ -44,7 +45,7 @@ class ShowDeletedMessagesPatch : BytecodePatch(
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// Spoiler mode: Force set hasModAccess member to true in constructor // Spoiler mode: Force set hasModAccess member to true in constructor
DeletedMessageClickableSpanCtorFingerprint.result!!.mutableMethod.apply { DeletedMessageClickableSpanCtorFingerprint.result?.mutableMethod?.apply {
addInstructionsWithLabels( addInstructionsWithLabels(
implementation!!.instructions.lastIndex, /* place in front of return-void */ implementation!!.instructions.lastIndex, /* place in front of return-void */
""" """
@ -54,14 +55,14 @@ class ShowDeletedMessagesPatch : BytecodePatch(
""", """,
ExternalLabel("no_spoiler", getInstruction(implementation!!.instructions.lastIndex)) ExternalLabel("no_spoiler", getInstruction(implementation!!.instructions.lastIndex))
) )
} } ?: return DeletedMessageClickableSpanCtorFingerprint.toErrorResult()
// Spoiler mode: Disable setHasModAccess setter // Spoiler mode: Disable setHasModAccess setter
SetHasModAccessFingerprint.result!!.mutableMethod.addInstruction(0, "return-void") SetHasModAccessFingerprint.result?.mutableMethod?.addInstruction(0, "return-void")
?: return SetHasModAccessFingerprint.toErrorResult()
// Cross-out mode: Reformat span of deleted message // Cross-out mode: Reformat span of deleted message
ChatUtilCreateDeletedSpanFingerprint.result!!.mutableMethod.apply { ChatUtilCreateDeletedSpanFingerprint.result?.mutableMethod?.apply {
addInstructionsWithLabels( addInstructionsWithLabels(
0, 0,
""" """
@ -72,7 +73,7 @@ class ShowDeletedMessagesPatch : BytecodePatch(
""", """,
ExternalLabel("no_reformat", getInstruction(0)) ExternalLabel("no_reformat", getInstruction(0))
) )
} } ?: return ChatUtilCreateDeletedSpanFingerprint.toErrorResult()
SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences( SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences(
ListPreference( ListPreference(

View file

@ -3,6 +3,6 @@ package app.revanced.patches.twitch.chat.autoclaim.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility([Package("tv.twitch.android.app")]) @Compatibility([Package("tv.twitch.android.app", arrayOf("15.4.1"))])
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class AutoClaimChannelPointsCompatibility internal annotation class AutoClaimChannelPointsCompatibility

View file

@ -65,6 +65,7 @@ class AutoClaimChannelPointPatch : BytecodePatch(
ExternalLabel("auto_claim", getInstruction(lastIndex)) ExternalLabel("auto_claim", getInstruction(lastIndex))
) )
} ?: return CommunityPointsButtonViewDelegateFingerprint.toErrorResult() } ?: return CommunityPointsButtonViewDelegateFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View file

@ -1,10 +1,9 @@
package app.revanced.patches.twitch.debug.fingerprints package app.revanced.patches.twitch.debug.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object IsDebugConfigEnabledFingerprint : MethodFingerprint( object IsDebugConfigEnabledFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "isDebugConfigEnabled" methodDef.definingClass.endsWith("/BuildConfigUtil;") && methodDef.name == "isDebugConfigEnabled"
} }
) )

View file

@ -1,10 +1,9 @@
package app.revanced.patches.twitch.debug.fingerprints package app.revanced.patches.twitch.debug.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object IsOmVerificationEnabledFingerprint : MethodFingerprint( object IsOmVerificationEnabledFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "isOmVerificationEnabled" methodDef.definingClass.endsWith("/BuildConfigUtil;") && methodDef.name == "isOmVerificationEnabled"
} }
) )

View file

@ -1,10 +1,9 @@
package app.revanced.patches.twitch.debug.fingerprints package app.revanced.patches.twitch.debug.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object ShouldShowDebugOptionsFingerprint : MethodFingerprint( object ShouldShowDebugOptionsFingerprint : MethodFingerprint(
customFingerprint = { methodDef, _ -> customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "shouldShowDebugOptions" methodDef.definingClass.endsWith("/BuildConfigUtil;") && methodDef.name == "shouldShowDebugOptions"
} }
) )

View file

@ -1,5 +1,6 @@
package app.revanced.patches.twitch.debug.patch package app.revanced.patches.twitch.debug.patch
import app.revanced.extensions.toErrorResult
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
@ -38,18 +39,16 @@ class DebugModePatch : BytecodePatch(
IsOmVerificationEnabledFingerprint, IsOmVerificationEnabledFingerprint,
ShouldShowDebugOptionsFingerprint ShouldShowDebugOptionsFingerprint
).forEach { ).forEach {
with(it.result!!) { it.result?.mutableMethod?.apply {
with(mutableMethod) { addInstructions(
addInstructions( 0,
0, """
""" invoke-static {}, Lapp/revanced/twitch/patches/DebugModePatch;->isDebugModeEnabled()Z
invoke-static {}, Lapp/revanced/twitch/patches/DebugModePatch;->isDebugModeEnabled()Z move-result v0
move-result v0 return v0
return v0 """
""" )
) } ?: return it.toErrorResult()
}
}
} }
SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences( SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences(

View file

@ -1,5 +1,6 @@
package app.revanced.patches.twitch.misc.settings.bytecode.patch package app.revanced.patches.twitch.misc.settings.bytecode.patch
import app.revanced.extensions.toErrorResult
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
@ -45,7 +46,7 @@ class SettingsPatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// Hook onCreate to handle fragment creation // Hook onCreate to handle fragment creation
with(SettingsActivityOnCreateFingerprint.result!!) { SettingsActivityOnCreateFingerprint.result?.apply {
val insertIndex = mutableMethod.implementation!!.instructions.size - 2 val insertIndex = mutableMethod.implementation!!.instructions.size - 2
mutableMethod.addInstructionsWithLabels( mutableMethod.addInstructionsWithLabels(
insertIndex, insertIndex,
@ -57,20 +58,20 @@ class SettingsPatch : BytecodePatch(
""", """,
ExternalLabel("no_rv_settings_init", mutableMethod.getInstruction(insertIndex)) ExternalLabel("no_rv_settings_init", mutableMethod.getInstruction(insertIndex))
) )
} } ?: return SettingsActivityOnCreateFingerprint.toErrorResult()
// Create new menu item for settings menu // Create new menu item for settings menu
with(SettingsMenuItemEnumFingerprint.result!!) { SettingsMenuItemEnumFingerprint.result?.apply {
injectMenuItem( injectMenuItem(
REVANCED_SETTINGS_MENU_ITEM_NAME, REVANCED_SETTINGS_MENU_ITEM_NAME,
REVANCED_SETTINGS_MENU_ITEM_ID, REVANCED_SETTINGS_MENU_ITEM_ID,
REVANCED_SETTINGS_MENU_ITEM_TITLE_RES, REVANCED_SETTINGS_MENU_ITEM_TITLE_RES,
REVANCED_SETTINGS_MENU_ITEM_ICON_RES REVANCED_SETTINGS_MENU_ITEM_ICON_RES
) )
} } ?: return SettingsMenuItemEnumFingerprint.toErrorResult()
// Intercept settings menu creation and add new menu item // Intercept settings menu creation and add new menu item
with(MenuGroupsUpdatedFingerprint.result!!) { MenuGroupsUpdatedFingerprint.result?.apply {
mutableMethod.addInstructions( mutableMethod.addInstructions(
0, 0,
""" """
@ -79,10 +80,10 @@ class SettingsPatch : BytecodePatch(
move-result-object p1 move-result-object p1
""" """
) )
} } ?: return MenuGroupsUpdatedFingerprint.toErrorResult()
// Intercept onclick events for the settings menu // Intercept onclick events for the settings menu
with(MenuGroupsOnClickFingerprint.result!!) { MenuGroupsOnClickFingerprint.result?.apply {
val insertIndex = 0 val insertIndex = 0
mutableMethod.addInstructionsWithLabels( mutableMethod.addInstructionsWithLabels(
insertIndex, insertIndex,
@ -96,7 +97,7 @@ class SettingsPatch : BytecodePatch(
""", """,
ExternalLabel("no_rv_settings_onclick", mutableMethod.getInstruction(insertIndex)) ExternalLabel("no_rv_settings_onclick", mutableMethod.getInstruction(insertIndex))
) )
} } ?: return MenuGroupsOnClickFingerprint.toErrorResult()
addString("revanced_settings", "ReVanced Settings", false) addString("revanced_settings", "ReVanced Settings", false)
addString("revanced_reboot_message", "Twitch needs to restart to apply your changes. Restart now?", false) addString("revanced_reboot_message", "Twitch needs to restart to apply your changes. Restart now?", false)

View file

@ -7,14 +7,15 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
import app.revanced.patches.shared.settings.preference.impl.* import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.ad.general.annotation.HideAdsCompatibility import app.revanced.patches.youtube.ad.general.annotation.HideAdsCompatibility
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen
@DependsOn( @DependsOn(
dependencies = [ [
LithoFilterPatch::class, LithoFilterPatch::class,
SettingsPatch::class, SettingsPatch::class,
ResourceMappingPatch::class ResourceMappingPatch::class
@ -23,185 +24,7 @@ import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.P
@HideAdsCompatibility @HideAdsCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideAdsResourcePatch : ResourcePatch { class HideAdsResourcePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult { override fun execute(context: ResourceContext): PatchResult {
PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_hide_gray_separator",
StringResource("revanced_hide_gray_separator_title", "Hide gray separator"),
StringResource("revanced_hide_gray_separator_summary_on", "Gray separators are hidden"),
StringResource("revanced_hide_gray_separator_summary_off", "Gray separators are shown")
),
SwitchPreference(
"revanced_hide_channel_guidelines",
StringResource("revanced_hide_channel_guidelines_title", "Hide channel guidelines"),
StringResource(
"revanced_hide_channel_guidelines_summary_on",
"Channel guidelines are hidden"
),
StringResource(
"revanced_hide_channel_guidelines_summary_off",
"Channel guidelines are shown"
)
),
SwitchPreference(
"revanced_hide_chapter_teaser",
StringResource(
"revanced_hide_chapter_teaser_title",
"Hide chapter teaser under videos"
),
StringResource(
"revanced_hide_chapter_teaser_summary_on",
"Chapter teasers are hidden"
),
StringResource(
"revanced_hide_chapter_teaser_summary_off",
"Chapter teasers are shown"
)
),
SwitchPreference(
"revanced_hide_merchandise_banners",
StringResource("revanced_hide_merchandise_banners_title", "Hide merchandise banners"),
StringResource("revanced_hide_merchandise_banners_summary_on", "Merchandise banners are hidden"),
StringResource("revanced_hide_merchandise_banners_summary_off", "Merchandise banners are shown")
),
SwitchPreference(
"revanced_hide_community_posts",
StringResource("revanced_hide_community_posts_title", "Hide community posts"),
StringResource("revanced_hide_community_posts_summary_on", "Community posts are hidden"),
StringResource("revanced_hide_community_posts_summary_off", "Community posts are shown")
),
SwitchPreference(
"revanced_hide_compact_banner",
StringResource("revanced_hide_compact_banner_title", "Hide compact banners"),
StringResource("revanced_hide_compact_banner_summary_on", "Compact banners are hidden"),
StringResource("revanced_hide_compact_banner_summary_off", "Compact banners are shown")
),
SwitchPreference(
"revanced_hide_products_banner",
StringResource("revanced_hide_products_banner_title", "Hide banner to view products"),
StringResource("revanced_hide_products_banner_summary_on", "Banner is hidden"),
StringResource("revanced_hide_products_banner_summary_off", "Banner is shown")
),
SwitchPreference(
"revanced_hide_web_search_results",
StringResource("revanced_hide_web_search_results_title", "Hide web search results"),
StringResource("revanced_hide_web_search_results_summary_on", "Web search results are hidden"),
StringResource("revanced_hide_web_search_results_summary_off", "Web search results are shown")
),
SwitchPreference(
"revanced_hide_movies_section",
StringResource("revanced_hide_movies_section_title", "Hide movies section"),
StringResource("revanced_hide_movies_section_summary_on", "Movies section is hidden"),
StringResource("revanced_hide_movies_section_summary_off", "Movies section is shown")
),
SwitchPreference(
"revanced_hide_feed_survey",
StringResource("revanced_hide_feed_survey_title", "Hide feed surveys"),
StringResource("revanced_hide_feed_survey_summary_on", "Feed surveys are hidden"),
StringResource("revanced_hide_feed_survey_summary_off", "Feed surveys are shown")
),
SwitchPreference(
"revanced_hide_community_guidelines",
StringResource("revanced_hide_community_guidelines_title", "Hide community guidelines"),
StringResource(
"revanced_hide_community_guidelines_summary_on",
"Community guidelines are hidden"
),
StringResource(
"revanced_hide_community_guidelines_summary_off",
"Community guidelines are shown"
)
),
SwitchPreference(
"revanced_hide_subscribers_community_guidelines",
StringResource(
"revanced_hide_subscribers_community_guidelines_title",
"Hide subscribers community guidelines"
),
StringResource(
"revanced_hide_subscribers_community_guidelines_summary_on",
"Subscribers community guidelines are hidden"
),
StringResource(
"revanced_hide_subscribers_community_guidelines_summary_off",
"Subscribers community guidelines are shown"
)
),
SwitchPreference(
"revanced_hide_channel_member_shelf",
StringResource("revanced_hide_channel_member_shelf_title", "Hide channel member shelf"),
StringResource(
"revanced_hide_channel_member_shelf_summary_on",
"Channel member shelf is hidden"
),
StringResource(
"revanced_hide_channel_member_shelf_summary_off",
"Channel member shelf is shown"
)
),
SwitchPreference(
"revanced_hide_emergency_box",
StringResource("revanced_hide_emergency_box_title", "Hide emergency boxes"),
StringResource("revanced_hide_emergency_box_summary_on", "Emergency boxes are hidden"),
StringResource("revanced_hide_emergency_box_summary_off", "Emergency boxes are shown")
),
SwitchPreference(
"revanced_hide_info_panels",
StringResource("revanced_hide_info_panels_title", "Hide info panels"),
StringResource("revanced_hide_info_panels_summary_on", "Info panels are hidden"),
StringResource("revanced_hide_info_panels_summary_off", "Info panels are shown")
),
SwitchPreference(
"revanced_hide_medical_panels",
StringResource("revanced_hide_medical_panels_title", "Hide medical panels"),
StringResource("revanced_hide_medical_panels_summary_on", "Medical panels are hidden"),
StringResource("revanced_hide_medical_panels_summary_off", "Medical panels are shown")
),
SwitchPreference(
"revanced_hide_channel_bar",
StringResource("revanced_hide_channel_bar_title", "Hide channel bar"),
StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"),
StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown")
),
SwitchPreference(
"revanced_hide_quick_actions",
StringResource("revanced_hide_quick_actions_title", "Hide quick actions in fullscreen"),
StringResource("revanced_hide_quick_actions_summary_on", "Quick actions are hidden"),
StringResource("revanced_hide_quick_actions_summary_off", "Quick actions are shown")
),
SwitchPreference(
"revanced_hide_related_videos",
StringResource("revanced_hide_related_videos_title", "Hide related videos in quick actions"),
StringResource("revanced_hide_related_videos_summary_on", "Related videos are hidden"),
StringResource("revanced_hide_related_videos_summary_off", "Related videos are shown")
),
SwitchPreference(
"revanced_hide_image_shelf",
StringResource("revanced_hide_image_shelf", "Hide image shelf in search results"),
StringResource("revanced_hide_image_shelf_summary_on", "Image shelf is hidden"),
StringResource("revanced_hide_image_shelf_summary_off", "Image shelf is shown")
),
SwitchPreference(
"revanced_hide_audio_track_button",
StringResource("revanced_hide_audio_track_button_title", "Hide audio track button"),
StringResource("revanced_hide_audio_track_button_on", "Audio track button is hidden"),
StringResource("revanced_hide_audio_track_button_off", "Audio track button is shown")
),
SwitchPreference(
"revanced_hide_latest_posts_ads",
StringResource("revanced_hide_latest_posts_ads_title", "Hide latest posts"),
StringResource("revanced_hide_latest_posts_ads_summary_on", "Latest posts are hidden"),
StringResource("revanced_hide_latest_posts_ads_summary_off", "Latest posts are shown")
),
SwitchPreference(
"revanced_hide_mix_playlists",
StringResource("revanced_hide_mix_playlists_title", "Hide mix playlists"),
StringResource("revanced_hide_mix_playlists_summary_on", "Mix playlists are hidden"),
StringResource("revanced_hide_mix_playlists_summary_off", "Mix playlists are shown")
),
)
PreferenceScreen.ADS.addPreferences( PreferenceScreen.ADS.addPreferences(
SwitchPreference( SwitchPreference(
"revanced_hide_general_ads", "revanced_hide_general_ads",
@ -227,38 +50,28 @@ class HideAdsResourcePatch : ResourcePatch {
StringResource("revanced_hide_self_sponsor_ads_summary_on", "Self sponsored cards are hidden"), StringResource("revanced_hide_self_sponsor_ads_summary_on", "Self sponsored cards are hidden"),
StringResource("revanced_hide_self_sponsor_ads_summary_off", "Self sponsored cards are shown") StringResource("revanced_hide_self_sponsor_ads_summary_off", "Self sponsored cards are shown")
), ),
PreferenceScreen( SwitchPreference(
"revanced_custom_filter_preference_screen", "revanced_hide_products_banner",
StringResource("revanced_custom_filter_preference_screen_title", "Custom filter"), StringResource("revanced_hide_products_banner_title", "Hide banner to view products"),
listOf( StringResource("revanced_hide_products_banner_summary_on", "Banner is hidden"),
SwitchPreference( StringResource("revanced_hide_products_banner_summary_off", "Banner is shown")
"revanced_custom_filter", ),
StringResource( SwitchPreference(
"revanced_custom_filter_title", "revanced_hide_web_search_results",
"Enable custom filter" StringResource("revanced_hide_web_search_results_title", "Hide web search results"),
), StringResource("revanced_hide_web_search_results_summary_on", "Web search results are hidden"),
StringResource( StringResource("revanced_hide_web_search_results_summary_off", "Web search results are shown")
"revanced_custom_filter_summary_on", ),
"Custom filter is enabled" SwitchPreference(
), "revanced_hide_merchandise_banners",
StringResource( StringResource("revanced_hide_merchandise_banners_title", "Hide merchandise banners"),
"revanced_custom_filter_summary_off", StringResource("revanced_hide_merchandise_banners_summary_on", "Merchandise banners are hidden"),
"Custom filter is disabled" StringResource("revanced_hide_merchandise_banners_summary_off", "Merchandise banners are shown")
)
),
// TODO: This should be a dynamic ListPreference, which does not exist yet
TextPreference(
"revanced_custom_filter_strings",
StringResource("revanced_custom_filter_strings_title", "Custom filter"),
StringResource(
"revanced_custom_filter_strings_summary",
"Filter components by their name separated by a comma"
)
)
)
) )
) )
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
adAttributionId = ResourceMappingPatch.resourceMappings.single { it.name == "ad_attribution" }.id adAttributionId = ResourceMappingPatch.resourceMappings.single { it.name == "ad_attribution" }.id
return PatchResultSuccess() return PatchResultSuccess()
@ -266,5 +79,8 @@ class HideAdsResourcePatch : ResourcePatch {
internal companion object { internal companion object {
var adAttributionId: Long = -1 var adAttributionId: Long = -1
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/patches/components/AdsFilter;"
} }
} }

View file

@ -66,6 +66,14 @@ class HideButtonsPatch : ResourcePatch {
StringResource("revanced_hide_buttons_preference_screen_summary", "Hide or show buttons under videos") StringResource("revanced_hide_buttons_preference_screen_summary", "Hide or show buttons under videos")
) )
) )
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
return PatchResultSuccess() return PatchResultSuccess()
} }
private companion object {
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/patches/components/ButtonsFilter;"
}
} }

View file

@ -42,7 +42,7 @@ class AlbumCardsPatch : BytecodePatch(
"invoke-static {v$albumCardViewRegister}, " + "invoke-static {v$albumCardViewRegister}, " +
"Lapp/revanced/integrations/patches/HideAlbumCardsPatch;" + "Lapp/revanced/integrations/patches/HideAlbumCardsPatch;" +
"->" + "->" +
"hideAlbumCards(Landroid/view/View;)V" "hideAlbumCard(Landroid/view/View;)V"
) )
} }
} ?: return AlbumCardsFingerprint.toErrorResult() } ?: return AlbumCardsFingerprint.toErrorResult()

View file

@ -1,8 +0,0 @@
package app.revanced.patches.youtube.layout.hide.artistcards.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
@Target(AnnotationTarget.CLASS)
internal annotation class HideArtistCardCompatibility

View file

@ -1,37 +0,0 @@
package app.revanced.patches.youtube.layout.hide.artistcards.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.layout.hide.artistcards.annotations.HideArtistCardCompatibility
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
@Patch
@DependsOn([ResourceMappingPatch::class, LithoFilterPatch::class])
@Name("hide-artist-card")
@Description("Hides the artist card below the searchbar.")
@HideArtistCardCompatibility
@Version("0.0.1")
class HideArtistCardsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_hide_artist_cards",
StringResource("revanced_hide_artist_cards_title", "Hide artist cards"),
StringResource("revanced_hide_artist_cards_on", "Artist cards is hidden"),
StringResource("revanced_hide_artist_cards_off", "Artist cards is shown")
),
)
return PatchResultSuccess()
}
}

View file

@ -9,21 +9,23 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch
import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen
import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.youtube.layout.hide.comments.annotations.HideCommentsCompatibility import app.revanced.patches.youtube.layout.hide.comments.annotations.HideCommentsCompatibility
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
@Patch @Patch
@Name("comments") @Name("comments")
@Description("Hides components related to comments.") @Description("Hides components related to comments.")
@HideCommentsCompatibility @HideCommentsCompatibility
@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) @DependsOn([SettingsPatch::class, LithoFilterPatch::class])
@Version("0.0.1") @Version("0.0.1")
class CommentsPatch : ResourcePatch { class CommentsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult { override fun execute(context: ResourceContext): PatchResult {
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
PreferenceScreen( PreferenceScreen(
"revanced_comments_preference_screen", "revanced_comments_preference_screen",
@ -48,4 +50,8 @@ class CommentsPatch : ResourcePatch {
return PatchResultSuccess() return PatchResultSuccess()
} }
}
private companion object {
const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/CommentsFilter;"
}
}

View file

@ -1,9 +1,9 @@
package app.revanced.patches.youtube.misc.litho.filter.annotation package app.revanced.patches.youtube.layout.hide.general.annotations
import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package import app.revanced.patcher.annotation.Package
@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))])
@Target(AnnotationTarget.CLASS) @Target(AnnotationTarget.CLASS)
internal annotation class LithoFilterCompatibility internal annotation class HideLayoutComponentsCompatibility

View file

@ -0,0 +1,247 @@
package app.revanced.patches.youtube.layout.hide.general.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.settings.preference.impl.StringResource
import app.revanced.patches.shared.settings.preference.impl.SwitchPreference
import app.revanced.patches.shared.settings.preference.impl.TextPreference
import app.revanced.patches.youtube.layout.hide.general.annotations.HideLayoutComponentsCompatibility
import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen
@Patch
@Name("hide-layout-components")
@Description("Hides general layout components.")
@DependsOn([LithoFilterPatch::class, SettingsPatch::class])
@HideLayoutComponentsCompatibility
@Version("0.0.1")
class HideLayoutComponentsPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_hide_gray_separator",
StringResource("revanced_hide_gray_separator_title", "Hide gray separator"),
StringResource("revanced_hide_gray_separator_summary_on", "Gray separators are hidden"),
StringResource("revanced_hide_gray_separator_summary_off", "Gray separators are shown")
),
SwitchPreference(
"revanced_hide_channel_guidelines",
StringResource("revanced_hide_channel_guidelines_title", "Hide channel guidelines"),
StringResource(
"revanced_hide_channel_guidelines_summary_on",
"Channel guidelines are hidden"
),
StringResource(
"revanced_hide_channel_guidelines_summary_off",
"Channel guidelines are shown"
)
),
SwitchPreference(
"revanced_hide_expandable_chip",
StringResource(
"revanced_hide_expandable_chip_title",
"Hide the expandable chip under videos"
),
StringResource(
"revanced_hide_expandable_chip_summary_on",
"Expandable chips are hidden"
),
StringResource(
"revanced_hide_expandable_chip_summary_off",
"Expandable chips are shown"
)
),
SwitchPreference(
"revanced_hide_chapters",
StringResource(
"revanced_hide_chapters_title",
"Hide chapters in the video description"
),
StringResource(
"revanced_hide_chapters_summary_on",
"Chapters are hidden"
),
StringResource(
"revanced_hide_chapters_summary_off",
"Chapters are shown"
)
),
SwitchPreference(
"revanced_hide_community_posts",
StringResource("revanced_hide_community_posts_title", "Hide community posts"),
StringResource("revanced_hide_community_posts_summary_on", "Community posts are hidden"),
StringResource("revanced_hide_community_posts_summary_off", "Community posts are shown")
),
SwitchPreference(
"revanced_hide_compact_banner",
StringResource("revanced_hide_compact_banner_title", "Hide compact banners"),
StringResource("revanced_hide_compact_banner_summary_on", "Compact banners are hidden"),
StringResource("revanced_hide_compact_banner_summary_off", "Compact banners are shown")
),
SwitchPreference(
"revanced_hide_movies_section",
StringResource("revanced_hide_movies_section_title", "Hide movies section"),
StringResource("revanced_hide_movies_section_summary_on", "Movies section is hidden"),
StringResource("revanced_hide_movies_section_summary_off", "Movies section is shown")
),
SwitchPreference(
"revanced_hide_feed_survey",
StringResource("revanced_hide_feed_survey_title", "Hide feed surveys"),
StringResource("revanced_hide_feed_survey_summary_on", "Feed surveys are hidden"),
StringResource("revanced_hide_feed_survey_summary_off", "Feed surveys are shown")
),
SwitchPreference(
"revanced_hide_community_guidelines",
StringResource("revanced_hide_community_guidelines_title", "Hide community guidelines"),
StringResource(
"revanced_hide_community_guidelines_summary_on",
"Community guidelines are hidden"
),
StringResource(
"revanced_hide_community_guidelines_summary_off",
"Community guidelines are shown"
)
),
SwitchPreference(
"revanced_hide_subscribers_community_guidelines",
StringResource(
"revanced_hide_subscribers_community_guidelines_title",
"Hide subscribers community guidelines"
),
StringResource(
"revanced_hide_subscribers_community_guidelines_summary_on",
"Subscribers community guidelines are hidden"
),
StringResource(
"revanced_hide_subscribers_community_guidelines_summary_off",
"Subscribers community guidelines are shown"
)
),
SwitchPreference(
"revanced_hide_channel_member_shelf",
StringResource("revanced_hide_channel_member_shelf_title", "Hide channel member shelf"),
StringResource(
"revanced_hide_channel_member_shelf_summary_on",
"Channel member shelf is hidden"
),
StringResource(
"revanced_hide_channel_member_shelf_summary_off",
"Channel member shelf is shown"
)
),
SwitchPreference(
"revanced_hide_emergency_box",
StringResource("revanced_hide_emergency_box_title", "Hide emergency boxes"),
StringResource("revanced_hide_emergency_box_summary_on", "Emergency boxes are hidden"),
StringResource("revanced_hide_emergency_box_summary_off", "Emergency boxes are shown")
),
SwitchPreference(
"revanced_hide_info_panels",
StringResource("revanced_hide_info_panels_title", "Hide info panels"),
StringResource("revanced_hide_info_panels_summary_on", "Info panels are hidden"),
StringResource("revanced_hide_info_panels_summary_off", "Info panels are shown")
),
SwitchPreference(
"revanced_hide_medical_panels",
StringResource("revanced_hide_medical_panels_title", "Hide medical panels"),
StringResource("revanced_hide_medical_panels_summary_on", "Medical panels are hidden"),
StringResource("revanced_hide_medical_panels_summary_off", "Medical panels are shown")
),
SwitchPreference(
"revanced_hide_channel_bar",
StringResource("revanced_hide_channel_bar_title", "Hide channel bar"),
StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"),
StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown")
),
SwitchPreference(
"revanced_hide_quick_actions",
StringResource("revanced_hide_quick_actions_title", "Hide quick actions in fullscreen"),
StringResource("revanced_hide_quick_actions_summary_on", "Quick actions are hidden"),
StringResource("revanced_hide_quick_actions_summary_off", "Quick actions are shown")
),
SwitchPreference(
"revanced_hide_related_videos",
StringResource("revanced_hide_related_videos_title", "Hide related videos in quick actions"),
StringResource("revanced_hide_related_videos_summary_on", "Related videos are hidden"),
StringResource("revanced_hide_related_videos_summary_off", "Related videos are shown")
),
SwitchPreference(
"revanced_hide_image_shelf",
StringResource("revanced_hide_image_shelf", "Hide image shelf in search results"),
StringResource("revanced_hide_image_shelf_summary_on", "Image shelf is hidden"),
StringResource("revanced_hide_image_shelf_summary_off", "Image shelf is shown")
),
SwitchPreference(
"revanced_hide_audio_track_button",
StringResource("revanced_hide_audio_track_button_title", "Hide audio track button"),
StringResource("revanced_hide_audio_track_button_on", "Audio track button is hidden"),
StringResource("revanced_hide_audio_track_button_off", "Audio track button is shown")
),
SwitchPreference(
"revanced_hide_latest_posts_ads",
StringResource("revanced_hide_latest_posts_ads_title", "Hide latest posts"),
StringResource("revanced_hide_latest_posts_ads_summary_on", "Latest posts are hidden"),
StringResource("revanced_hide_latest_posts_ads_summary_off", "Latest posts are shown")
),
SwitchPreference(
"revanced_hide_mix_playlists",
StringResource("revanced_hide_mix_playlists_title", "Hide mix playlists"),
StringResource("revanced_hide_mix_playlists_summary_on", "Mix playlists are hidden"),
StringResource("revanced_hide_mix_playlists_summary_off", "Mix playlists are shown")
),
SwitchPreference(
"revanced_hide_artist_cards",
StringResource("revanced_hide_artist_cards_title", "Hide artist cards"),
StringResource("revanced_hide_artist_cards_on", "Artist cards is hidden"),
StringResource("revanced_hide_artist_cards_off", "Artist cards is shown")
),
app.revanced.patches.shared.settings.preference.impl.PreferenceScreen(
"revanced_custom_filter_preference_screen",
StringResource("revanced_custom_filter_preference_screen_title", "Custom filter"),
listOf(
SwitchPreference(
"revanced_custom_filter",
StringResource(
"revanced_custom_filter_title",
"Enable custom filter"
),
StringResource(
"revanced_custom_filter_summary_on",
"Custom filter is enabled"
),
StringResource(
"revanced_custom_filter_summary_off",
"Custom filter is disabled"
)
),
// TODO: This should be a dynamic ListPreference, which does not exist yet
TextPreference(
"revanced_custom_filter_strings",
StringResource("revanced_custom_filter_strings_title", "Custom filter"),
StringResource(
"revanced_custom_filter_strings_summary",
"Filter components by their name separated by a comma"
)
)
)
)
)
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
return PatchResultSuccess()
}
internal companion object {
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/patches/components/LayoutComponentsFilter;"
}
}

View file

@ -49,6 +49,8 @@ class HideShortsComponentsPatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR)
// region Hide the Shorts shelf. // region Hide the Shorts shelf.
ReelConstructorFingerprint.result?.let { ReelConstructorFingerprint.result?.let {
@ -59,7 +61,7 @@ class HideShortsComponentsPatch : BytecodePatch(
injectHideViewCall( injectHideViewCall(
insertIndex, insertIndex,
viewRegister, viewRegister,
CLASS_DESCRIPTOR, FILTER_CLASS_DESCRIPTOR,
"hideShortsShelf" "hideShortsShelf"
) )
} }
@ -89,7 +91,7 @@ class HideShortsComponentsPatch : BytecodePatch(
val viewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA val viewRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction( addInstruction(
checkCastIndex + 1, checkCastIndex + 1,
"sput-object v$viewRegister, $CLASS_DESCRIPTOR->pivotBar:" + "sput-object v$viewRegister, $FILTER_CLASS_DESCRIPTOR->pivotBar:" +
"Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;"
) )
} }
@ -102,7 +104,7 @@ class HideShortsComponentsPatch : BytecodePatch(
throw RenderBottomNavigationBarFingerprint.toErrorResult() throw RenderBottomNavigationBarFingerprint.toErrorResult()
RenderBottomNavigationBarFingerprint.result!!.mutableMethod.apply { RenderBottomNavigationBarFingerprint.result!!.mutableMethod.apply {
addInstruction(0, "invoke-static { }, $CLASS_DESCRIPTOR->hideNavigationBar()V") addInstruction(0, "invoke-static { }, $FILTER_CLASS_DESCRIPTOR->hideNavigationBar()V")
} }
} ?: return RenderBottomNavigationBarParentFingerprint.toErrorResult() } ?: return RenderBottomNavigationBarParentFingerprint.toErrorResult()
@ -115,7 +117,7 @@ class HideShortsComponentsPatch : BytecodePatch(
addInstruction( addInstruction(
insertIndex, insertIndex,
"invoke-static { v$viewRegister }, $CLASS_DESCRIPTOR->" + "invoke-static { v$viewRegister }, $FILTER_CLASS_DESCRIPTOR->" +
"hideNavigationBar(Landroid/view/View;)Landroid/view/View;" "hideNavigationBar(Landroid/view/View;)Landroid/view/View;"
) )
} }
@ -127,7 +129,7 @@ class HideShortsComponentsPatch : BytecodePatch(
} }
private companion object { private companion object {
private const val CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/ShortsFilter;" private const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/ShortsFilter;"
private enum class ShortsButtons(private val resourceName: String, private val methodName: String) { private enum class ShortsButtons(private val resourceName: String, private val methodName: String) {
COMMENTS("reel_dyn_comment", "hideShortsCommentsButton"), COMMENTS("reel_dyn_comment", "hideShortsCommentsButton"),
@ -139,7 +141,7 @@ class HideShortsComponentsPatch : BytecodePatch(
val setIdIndex = referencedIndex + 1 val setIdIndex = referencedIndex + 1
val viewRegister = method.getInstruction<FiveRegisterInstruction>(setIdIndex).registerC val viewRegister = method.getInstruction<FiveRegisterInstruction>(setIdIndex).registerC
method.injectHideViewCall(setIdIndex, viewRegister, CLASS_DESCRIPTOR, methodName) method.injectHideViewCall(setIdIndex, viewRegister, FILTER_CLASS_DESCRIPTOR, methodName)
} }
} }
} }

View file

@ -42,7 +42,7 @@ import org.jf.dexlib2.iface.reference.StringReference
@Patch @Patch
@DependsOn( @DependsOn(
dependencies = [ [
IntegrationsPatch::class, IntegrationsPatch::class,
VideoIdPatch::class, VideoIdPatch::class,
// Required to skip segments on time. // Required to skip segments on time.

View file

@ -0,0 +1,11 @@
package app.revanced.patches.youtube.misc.litho.filter.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object LithoFilterFingerprint : MethodFingerprint(
customFingerprint = custom@{ method, classDef ->
if (method.name != "<clinit>") return@custom false
classDef.type.endsWith("LithoFilterPatch;")
}
)

View file

@ -4,8 +4,11 @@ import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
@ -14,30 +17,28 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.litho.filter.annotation.LithoFilterCompatibility import app.revanced.patches.youtube.misc.litho.filter.fingerprints.*
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ComponentContextParserFingerprint import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.EmptyComponentBuilderFingerprint
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ProtobufBufferFingerprint
import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ReadComponentIdentifierFingerprint
import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import java.io.Closeable
@DependsOn([IntegrationsPatch::class]) @DependsOn([IntegrationsPatch::class])
@Description("Hooks the method which parses the bytes into a ComponentContext to filter components.") @Description("Hooks the method which parses the bytes into a ComponentContext to filter components.")
@LithoFilterCompatibility
@Version("0.0.1") @Version("0.0.1")
class LithoFilterPatch : BytecodePatch( class LithoFilterPatch : BytecodePatch(
listOf(ComponentContextParserFingerprint) listOf(ComponentContextParserFingerprint, LithoFilterFingerprint)
) { ), Closeable {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
ComponentContextParserFingerprint.result?.also { ComponentContextParserFingerprint.result?.also {
arrayOf( arrayOf(
EmptyComponentBuilderFingerprint, ReadComponentIdentifierFingerprint, ProtobufBufferFingerprint EmptyComponentBuilderFingerprint,
ReadComponentIdentifierFingerprint,
ProtobufBufferFingerprint
).forEach { fingerprint -> ).forEach { fingerprint ->
if (!fingerprint.resolve(context, it.mutableMethod, it.mutableClass)) if (fingerprint.resolve(context, it.mutableMethod, it.mutableClass)) return@forEach
return fingerprint.toErrorResult() return fingerprint.toErrorResult()
} }
}?.let { result -> }?.let { result ->
val builderMethodIndex = EmptyComponentBuilderFingerprint.patternScanEndIndex val builderMethodIndex = EmptyComponentBuilderFingerprint.patternScanEndIndex
@ -45,16 +46,28 @@ class LithoFilterPatch : BytecodePatch(
result.mutableMethod.apply { result.mutableMethod.apply {
val insertHookIndex = result.scanResult.patternScanResult!!.endIndex val insertHookIndex = result.scanResult.patternScanResult!!.endIndex
val builderMethodDescriptor = getInstruction(builderMethodIndex).descriptor
val emptyComponentFieldDescriptor = getInstruction(emptyComponentFieldIndex).descriptor // region Get free registers that this patch uses
// Register is overwritten right after it is used in this patch, therefore free to clobber. // Registers are overwritten right after they are used in this patch, therefore free to clobber.
val free = getInstruction<TwoRegisterInstruction>(insertHookIndex - 1).registerA
val free2 = getInstruction<OneRegisterInstruction>(insertHookIndex).registerA val freeRegistersInstruction = getInstruction<FiveRegisterInstruction>(insertHookIndex - 2)
// Later used to store the protobuf buffer object.
val free1 = getInstruction<OneRegisterInstruction>(insertHookIndex).registerA
// Later used to store the identifier of the component.
// This register currently holds a reference to the StringBuilder object
// that is required before clobbering.
val free2 = freeRegistersInstruction.registerC
@Suppress("UnnecessaryVariable") @Suppress("UnnecessaryVariable")
// The register, this patch clobbers, is previously used for the StringBuilder, val stringBuilderRegister = free2
// later on a new StringBuilder is instantiated on it.
val stringBuilderRegister = free // endregion
// region Get references that this patch needs
val builderMethodDescriptor = getInstruction(builderMethodIndex).descriptor
val emptyComponentFieldDescriptor = getInstruction(emptyComponentFieldIndex).descriptor
val identifierRegister = val identifierRegister =
getInstruction<OneRegisterInstruction>(ReadComponentIdentifierFingerprint.patternScanEndIndex).registerA getInstruction<OneRegisterInstruction>(ReadComponentIdentifierFingerprint.patternScanEndIndex).registerA
@ -69,57 +82,87 @@ class LithoFilterPatch : BytecodePatch(
getInstruction(ProtobufBufferFingerprint.patternScanEndIndex - 1).descriptor getInstruction(ProtobufBufferFingerprint.patternScanEndIndex - 1).descriptor
val protobufBufferFieldDescriptor = "$protobufBufferRefTypeDescriptor->b:Ljava/nio/ByteBuffer;" val protobufBufferFieldDescriptor = "$protobufBufferRefTypeDescriptor->b:Ljava/nio/ByteBuffer;"
// endregion
// region Patch the method
// Insert the instructions that are responsible
// to return an EmptyComponent instead of the original component if the filter method returns false.
addInstructionsWithLabels( addInstructionsWithLabels(
insertHookIndex, // right after setting the component.pathBuilder field. insertHookIndex,
""" """
# Get the protobuf buffer object. # Get the protobuf buffer object.
move-object/from16 v$free2, p$protobufParameterNumber move-object/from16 v$free1, p$protobufParameterNumber
iget-object v$free2, v$free2, $protobufBufferRefTypeRefFieldDescriptor iget-object v$free1, v$free1, $protobufBufferRefTypeRefFieldDescriptor
check-cast v$free2, $protobufBufferRefTypeDescriptor check-cast v$free1, $protobufBufferRefTypeDescriptor
# Register "free" now holds the protobuf buffer object # Register "free" now holds the protobuf buffer object
iget-object v$free2, v$free2, $protobufBufferFieldDescriptor iget-object v$free1, v$free1, $protobufBufferFieldDescriptor
# Invoke the filter method. # Invoke the filter method.
invoke-static { v$stringBuilderRegister, v$identifierRegister, v$free2 }, $FILTER_METHOD_DESCRIPTOR invoke-static { v$stringBuilderRegister, v$identifierRegister, v$free1 }, $FILTER_METHOD_DESCRIPTOR
move-result v$free move-result v$free1
if-eqz v$free, :not_an_ad if-eqz v$free1, :unfiltered
# If the filter method returned true, then return a replacement empty component. move-object/from16 v$free2, p1
invoke-static {v$free2}, $builderMethodDescriptor
move-object/from16 v$free, p1 move-result-object v$free2
invoke-static {v$free}, $builderMethodDescriptor iget-object v$free2, v$free2, $emptyComponentFieldDescriptor
move-result-object v$free return-object v$free2
iget-object v$free, v$free, $emptyComponentFieldDescriptor
return-object v$free
""", """,
ExternalLabel("not_an_ad", getInstruction(insertHookIndex)) // Used to jump over the instruction which block the component from being created.
ExternalLabel("unfiltered", getInstruction(insertHookIndex))
) )
// endregion
} }
} ?: return ComponentContextParserFingerprint.toErrorResult() } ?: return ComponentContextParserFingerprint.toErrorResult()
LithoFilterFingerprint.result?.mutableMethod?.apply {
removeInstructions(2, 4) // Remove dummy filter.
addFilter = { classDescriptor ->
addInstructions(
2,
"""
new-instance v1, $classDescriptor
invoke-direct {v1}, $classDescriptor-><init>()V
const/4 v2, ${filterCount++}
aput-object v1, v0, v2
"""
)
}
} ?: return LithoFilterFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
private companion object { override fun close() = LithoFilterFingerprint.result!!
.mutableMethod.replaceInstruction(0, "const/4 v0, $filterCount")
companion object {
private val MethodFingerprint.patternScanResult private val MethodFingerprint.patternScanResult
get() = result!!.scanResult.patternScanResult!! get() = result!!.scanResult.patternScanResult!!
val MethodFingerprint.patternScanEndIndex private val MethodFingerprint.patternScanEndIndex
get() = patternScanResult.endIndex get() = patternScanResult.endIndex
val MethodFingerprint.patternScanStartIndex private val MethodFingerprint.patternScanStartIndex
get() = patternScanResult.startIndex get() = patternScanResult.startIndex
val Instruction.descriptor private val Instruction.descriptor
get() = (this as ReferenceInstruction).reference.toString() get() = (this as ReferenceInstruction).reference.toString()
const val FILTER_METHOD_DESCRIPTOR = private const val FILTER_METHOD_DESCRIPTOR =
"Lapp/revanced/integrations/patches/components/LithoFilterPatch;" + "Lapp/revanced/integrations/patches/components/LithoFilterPatch;" +
"->filter(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/nio/ByteBuffer;)Z" "->filter(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/nio/ByteBuffer;)Z"
internal lateinit var addFilter: (String) -> Unit
private set
private var filterCount = 0
} }
} }