From e0ec9c687b4190899f836425b96a16d04925cbaf Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 9 Feb 2024 00:17:34 +0000 Subject: [PATCH 01/52] chore(release): 4.3.0-dev.1 [skip ci] # [4.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0-dev.1) (2024-02-09) ### Features * **YouTube - Change start page:** Add more start pages ([cc1d9b7](https://github.com/ReVanced/revanced-patches/commit/cc1d9b743633c619fb6acc428e884c1c9b53e10b)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ac41350..26f6670e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0-dev.1) (2024-02-09) + + +### Features + +* **YouTube - Change start page:** Add more start pages ([cc1d9b7](https://github.com/ReVanced/revanced-patches/commit/cc1d9b743633c619fb6acc428e884c1c9b53e10b)) + # [4.2.0](https://github.com/ReVanced/revanced-patches/compare/v4.1.0...v4.2.0) (2024-02-08) diff --git a/gradle.properties b/gradle.properties index bf444fa6..b762d0e8 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.2.0 +version = 4.3.0-dev.1 From f15ef3f63460254236185f8e22c9395db4db9465 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Fri, 9 Feb 2024 03:36:05 +0100 Subject: [PATCH 02/52] feat(Sync for Reddit): Add `Fix /s/ links` patch --- api/revanced-patches.api | 6 ++++ .../syncforreddit/fix/slink/FixSLinksPatch.kt | 32 +++++++++++++++++++ .../LinkHelperOpenLinkFingerprint.kt | 7 ++++ 3 files changed, 45 insertions(+) create mode 100644 src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/LinkHelperOpenLinkFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 10956e60..25de72ba 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -550,6 +550,12 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/detec public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/reddit/layout/disablescreenshotpopup/DisableScreenshotPopupPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt new file mode 100644 index 00000000..09fa4e37 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/FixSLinksPatch.kt @@ -0,0 +1,32 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints.LinkHelperOpenLinkFingerprint +import app.revanced.util.exception + +@Patch( + name = "Fix /s/ links", + description = "Fixes the issue where /s/ links do not work.", + compatiblePackages = [ + CompatiblePackage("com.laurencedawson.reddit_sync"), + CompatiblePackage("com.laurencedawson.reddit_sync.pro"), + CompatiblePackage("com.laurencedawson.reddit_sync.dev") + ], + requiresIntegrations = true +) +object FixSLinksPatch : BytecodePatch( + setOf(LinkHelperOpenLinkFingerprint) +) { + override fun execute(context: BytecodeContext) = + LinkHelperOpenLinkFingerprint.result?.mutableMethod?.addInstructions( + 1, + """ + invoke-static { p3 }, Lapp/revanced/integrations/syncforreddit/FixSLinksPatch;->resolveSLink(Ljava/lang/String;)Ljava/lang/String; + move-result-object p3 + """ + ) ?: throw LinkHelperOpenLinkFingerprint.exception +} diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/LinkHelperOpenLinkFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/LinkHelperOpenLinkFingerprint.kt new file mode 100644 index 00000000..a84de6b2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/fix/slink/fingerprints/LinkHelperOpenLinkFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.reddit.customclients.syncforreddit.fix.slink.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object LinkHelperOpenLinkFingerprint: MethodFingerprint( + strings = listOf("Link title: ") +) From b5caab6649316e5ad688f4dbcf6662f5ee8a38e8 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 9 Feb 2024 02:47:31 +0000 Subject: [PATCH 03/52] chore(release): 4.3.0-dev.2 [skip ci] # [4.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.1...v4.3.0-dev.2) (2024-02-09) ### Features * **Sync for Reddit:** Add `Fix /s/ links` patch ([f15ef3f](https://github.com/ReVanced/revanced-patches/commit/f15ef3f63460254236185f8e22c9395db4db9465)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- patches.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26f6670e..18ae9af2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.1...v4.3.0-dev.2) (2024-02-09) + + +### Features + +* **Sync for Reddit:** Add `Fix /s/ links` patch ([f15ef3f](https://github.com/ReVanced/revanced-patches/commit/f15ef3f63460254236185f8e22c9395db4db9465)) + # [4.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0-dev.1) (2024-02-09) diff --git a/gradle.properties b/gradle.properties index b762d0e8..3153271a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.1 +version = 4.3.0-dev.2 diff --git a/patches.json b/patches.json index 4c3f5f93..cbc74ff6 100644 --- a/patches.json +++ b/patches.json @@ -1 +1 @@ -[{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":["2.2 build 016"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove device restrictions","description":"Removes restrictions from using the app on any device. Requires mounting patched app over original.","compatiblePackages":[{"name":"com.google.android.apps.recorder","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove bootloader detection","description":"Removes the check for an unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable mandatory login","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove broadcasts restriction","description":"Enables starting/stopping NetGuard via broadcasts.","compatiblePackages":[{"name":"eu.faircode.netguard","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove debugging detection","description":"Removes the USB and wireless debugging checks.","compatiblePackages":[{"name":"com.scb.phone","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":["4.29"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass root checks","description":"Removes the restriction to use the app with root permissions or on a custom ROM.","compatiblePackages":[{"name":"it.ipzs.cieid","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show deleted messages","description":"Shows deleted chat messages behind a clickable spoiler.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Auto claim channel points","description":"Automatically claim Channel Points.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block audio ads","description":"Blocks audio ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block embedded ads","description":"Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block video ads","description":"Blocks video ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds settings menu to Twitch.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Debug mode","description":"Enables Twitch\u0027s internal debugging mode.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable switching emoji to sticker","description":"Disables switching from emoji to sticker search mode in message input field.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable typing indicator","description":"Disables the indicator while typing a message.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide inbox ads","description":"Hides ads in inbox.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides most of the ads across the app.","compatiblePackages":[{"name":"com.myfitnesspal.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide story ads","description":"Hides the ads in the Facebook app stories.","compatiblePackages":[{"name":"com.facebook.katana","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove badge tab","description":"Removes the badge tab from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove notification badge","description":"Removes the red notification badge from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":["10.1.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timeline ads","description":"Removes ads from the timeline.","compatiblePackages":[{"name":"com.instagram.android","versions":["275.0.0.27.98"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove file size limit","description":"Allows opening files larger than 2 MB in the text editor.","compatiblePackages":[{"name":"pl.solidexplorer2","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Adds options to remove general ads.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Video ads","description":"Adds an option to remove ads in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Spoof device dimensions","description":"Adds an option to spoof the device dimensions which unlocks higher video qualities if they aren\u0027t available on the device.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable zoom haptics","description":"Adds an option to disable haptics when zooming.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass URL redirects","description":"Adds an option to bypass URL redirects and open the original URL directly.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Open links externally","description":"Adds an option to always open links in your browser instead of in the in-app-browser.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove tracking query parameter","description":"Adds an option to remove the tracking info from links you share.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Always repeat","description":"Adds an option to always repeat videos when they end.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Announcements","description":"Adds an option to show announcements from ReVanced on app startup.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Client spoof","description":"Adds options to spoof the client to allow video playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable debugging","description":"Adds options for debugging.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Unlocks options for picture-in-picture and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Seekbar tapping","description":"Adds an option to enable tap-to-seek on the seekbar of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable slide to seek","description":"Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable precise seeking gesture","description":"Adds an option to disable precise seeking when swiping up on the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Copy video URL","description":"Adds options to display buttons in the video player to copy video URLs.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"External downloads","description":"Adds support to download and save YouTube videos using an external downloader app.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove viewer discretion dialog","description":"Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds options to enable and configure volume and brightness swipe controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove player controls background","description":"Removes the dark background surrounding the video player controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Custom player overlay opacity","description":"Adds an option to change the opacity of the video player background when player controls are visible.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old seekbar thumbnails","description":"Adds an option to restore the old seekbar thumbnails that appear above the seekbar while seeking instead of fullscreen thumbnails.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof app version","description":"Adds an option to trick YouTube into thinking you are running an older version of the app. This can be used to restore old UI elements and features.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Return YouTube Dislike","description":"Adds an option to show the dislike count of videos using the Return YouTube Dislike API.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Adds options to hide menu items that appear when pressing the gear icon in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Adds an option to hide info cards that creators add in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Adds an option to hide the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Adds an option to hide suggested video cards at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Adds options to hide components related to comments.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable rolling number animations","description":"Adds an option to disable rolling number animations of video view count, user likes, and upload time.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable fullscreen ambient mode","description":"Adds an option to disable the ambient mode when in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide floating microphone button","description":"Adds an option to hide the floating microphone button when searching.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide layout components","description":"Adds options to hide general layout components.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Adds options to hide components related to YouTube Shorts.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide \u0027Load more\u0027 button","description":"Adds an option to hide the button under videos that loads similar videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide crowdfunding box","description":"Adds an option to hide the crowdfunding box between the player and video description.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Adds an option to hide the timestamp in the bottom left of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide breaking news shelf","description":"Adds an option to hide the breaking news shelf on the homepage tab.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable suggested video end screen","description":"Adds an option to disable the suggested video end screen at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide album cards","description":"Adds an option to hide album cards below artist descriptions.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide filter bar","description":"Adds options to hide the category bar at the top of video feeds.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom branding","description":"Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"appName","default":"YouTube ReVanced","values":{"YouTube ReVanced":"YouTube ReVanced","YT ReVanced":"YT ReVanced","YT":"YT","YouTube":"YouTube"},"title":"App name","description":"The name of the app.","required":false},{"key":"iconPath","default":"ReVanced*Logo","values":{"ReVanced Logo":"ReVanced*Logo"},"title":"App icon","description":"The path to a folder containing the following folders:\n\n- mipmap-xxxhdpi\n- mipmap-xxhdpi\n- mipmap-xhdpi\n- mipmap-hdpi\n- mipmap-mdpi\n\nEach of these folders has to have the following files:\n\n- adaptiveproduct_youtube_background_color_108.png\n- adaptiveproduct_youtube_foreground_color_108.png\n- ic_launcher.png\n- ic_launcher_round.png","required":false}]},{"name":"Change header","description":"Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"header","default":"ReVanced (borderless logo)","values":{"YouTube":"yt_wordmark_header","YouTube Premium":"yt_premium_wordmark_header","ReVanced":"ReVanced","ReVanced (borderless logo)":"ReVanced (borderless logo)"},"title":"Header","description":"Either a header name or a path to a custom header folder to use in the top bar.\nThe path to a folder must contain one or more of the following folders matching the DPI of your device:\n\n- drawable-xxxhdpi\n- drawable-xxhdpi\n- drawable-xhdpi\n- drawable-mdpi\n- drawable-hdpi\n\nThese folders must contain the following files:\n\n- yt_wordmark_header_light.png\n- yt_wordmark_header_dark.png","required":true}]},{"name":"Hide player buttons","description":"Adds an option to hide the previous and next buttons in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Navigation buttons","description":"Adds options to hide and change navigation buttons (such as the Shorts button).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide video action buttons","description":"Adds options to hide action buttons (such as the Download button) under videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide cast button","description":"Adds an option to hide the cast button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Adds an option to hide the captions button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide autoplay button","description":"Adds an option to hide the autoplay button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable tablet layout","description":"Adds an option to spoof the device form factor to a tablet which enables the tablet layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable resuming Shorts on startup","description":"Adds an option to disable the Shorts player from resuming on app startup when Shorts were last being watched.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change start page","description":"Adds an option to set which page the app opens in instead of the homepage.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Theme","description":"Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[{"key":"darkThemeBackgroundColor","default":"@android:color/black","values":{"Amoled black":"@android:color/black","Material You":"@android:color/system_neutral1_900","Classic (old YouTube)":"#FF212121","Catppuccin (Mocha)":"#FF181825","Dark pink":"#FF290025","Dark blue":"#FF001029","Dark green":"#FF002905","Dark yellow":"#FF282900","Dark orange":"#FF291800","Dark red":"#FF290000"},"title":"Dark theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false},{"key":"lightThemeBackgroundColor","default":"@android:color/white","values":{"White":"@android:color/white","Material You":"@android:color/system_neutral1_50","Catppuccin (Latte)":"#FFE6E9EF","Light pink":"#FFFCCFF3","Light blue":"#FFD1E0FF","Light green":"#FFCCFFCC","Light yellow":"#FFFDFFCC","Light orange":"#FFFFE6CC","Light red":"#FFFFD6D6"},"title":"Light theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false}]},{"name":"Disable auto captions","description":"Adds an option to disable captions from being automatically enabled.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Wide searchbar","description":"Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Adds an option to enable the tablet mini player layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Alternative thumbnails","description":"Adds options to replace video thumbnails using the DeArrow API or image captures from the video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable player popup panels","description":"Adds an option to disable panels (such as live chat) from opening automatically.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds an option to remember the last video quality selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"HDR auto brightness","description":"Adds an option to make the brightness of HDR videos follow the system default.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds options to customize available playback speeds and to remember the last playback speed selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old video quality menu","description":"Adds an option to restore the old video quality menu with specific video resolution options.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable Tumblr Live","description":"Disable the Tumblr Live tab button and dashboard carousel.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable gift message popup","description":"Disables the popup suggesting to buy TumblrMart items for other people.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable in-app update","description":"Disables the in-app update check and update prompt.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable blog notification reminder","description":"Disables the reminder to enable notifications for blogs you visit.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable dashboard ads","description":"Disables ads in the dashboard.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock plus","description":null,"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide update popup","description":"Prevents the update popup from showing up.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device ID","description":"Spoofs device ID to mitigate manual bans by developers.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Dynamic color","description":"Replaces the default X (Formerly Twitter) Blue with the user\u0027s Material You palette.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide recommended users","description":null,"compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides ads.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock downloads","description":"Unlocks the ability to download any video.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide view count","description":"Hides the view count of Posts.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Custom theme","description":"Applies a custom theme.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"backgroundColor","default":"@android:color/black","values":null,"title":"Primary background color","description":"The background color. Can be a hex color or a resource reference.","required":true},{"key":"backgroundColorSecondary","default":"#ff282828","values":null,"title":"Secondary background color","description":"The secondary background color. (e.g. search box, artist \u0026 podcast). Can be a hex color or a resource reference.","required":true},{"key":"accentColor","default":"#ff1ed760","values":null,"title":"Accent color","description":"The accent color (\u0027Spotify green\u0027 by default). Can be a hex color or a resource reference.","required":true},{"key":"accentColorPressed","default":"#ff169c46","values":null,"title":"Pressed dark theme accent color","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":true}]},{"name":"Enable on demand","description":"Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.","compatiblePackages":[{"name":"com.spotify.lite","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide premium navbar","description":"Removes the premium tab from the navbar.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Change package name","description":"Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"packageName","default":"Default","values":{"Default":"Default"},"title":"Package name","description":"The name of the package to rename the app to.","required":true}]},{"name":"Enable Android debugging","description":"Enables Android debugging capabilities. This can slow down the app.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Override certificate pinning","description":"Overrides certificate pinning, allowing to inspect traffic via a proxy.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Predictive back gesture","description":"Enables the predictive back gesture introduced on Android 13.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove screenshot restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Remove screen capture restriction","description":"Removes the restriction of capturing audio from apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Spoof SIM country","description":"Spoofs country information returned by the SIM card provider.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"networkCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Network ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false},{"key":"simCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Sim ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false}]},{"name":"Spoof Wi-Fi connection","description":"Spoofs an existing Wi-Fi connection.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Sanitize sharing links","description":"Removes (tracking) query parameters from the URLs when sharing links.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"free.reddit.news","versions":null},{"name":"reddit.news","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"dbrady://relay\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"infinity://localhost\".","required":true}]},{"name":"Unlock subscription","description":"Unlocks the subscription feature but requires a custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"o.o.joey","versions":null},{"name":"o.o.joey.pro","versions":null},{"name":"o.o.joey.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"https://127.0.0.1:65023/authorize_callback\".","required":true}]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"o.o.joey","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.rubenmayayo.reddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://rubenmayayo.com\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"me.ccrama.redditslide","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://www.ccrama.me\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.andrewshu.android.reddit","versions":null},{"name":"com.andrewshu.android.redditdonation","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"redditisfun://auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.onelouder.baconreader","versions":null},{"name":"com.onelouder.baconreader.premium","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://baconreader.com/auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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\".","required":true}]},{"name":"Disable Sync for Lemmy bottom sheet","description":"Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":["v23.06.30-13:39"]},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable screenshot popup","description":"Disables the popup that shows up when taking a screenshot.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium Reddit icons","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.awedea.nyx","versions":["2.2.7"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof signature","description":"Spoofs the signature of the app.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","compatiblePackages":[{"name":"com.ticktick.task","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Music video ads","description":"Removes ads in the music player.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Bypass certificate checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Permanent repeat","description":"Permanently remember your repeating preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Permanent shuffle","description":"Permanently remember your shuffle preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Codecs unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Exclusive audio playback","description":"Enables the option to play audio without video.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove upgrade button","description":"Removes the upgrade tab from the pivot bar.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Compact header","description":"Hides the music category bar at the top of the homepage.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Hide get premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback music","description":"Enables minimized playback on Kids music.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Background play","description":"Enables playing music in the background.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"jp.pxv.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show on lockscreen","description":"Shows student id and student ticket on lockscreen.","compatiblePackages":[{"name":"de.tudortmund.app","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Feed filter","description":"Removes ads, livestreams, stories, image videos and videos with a specific amount of views or likes from the feed.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SIM spoof","description":"Spoofs the information which is retrieved from the SIM card.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable login requirement","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Fix Google login","description":"Allows logging in with a Google account.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds ReVanced settings to TikTok.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show seekbar","description":"Shows progress bar for all video.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Downloads","description":"Removes download restrictions and changes the default path to download to.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Enables the playback speed option for all videos and retains the speed configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember clear display","description":"Remembers the clear display configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Promo code unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","compatiblePackages":[{"name":"de.dwd.warnapp","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable subscription suggestions","description":null,"compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock subscription features","description":"Unlocks \"Routes\", \"Matched Runs\" and \"Segment Efforts\".","compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Pro unlock","description":null,"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bka.serviceportal","versions":null}],"use":true,"requiresIntegrations":false,"options":[]}] \ No newline at end of file +[{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":["2.2 build 016"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove device restrictions","description":"Removes restrictions from using the app on any device. Requires mounting patched app over original.","compatiblePackages":[{"name":"com.google.android.apps.recorder","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove bootloader detection","description":"Removes the check for an unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable mandatory login","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove broadcasts restriction","description":"Enables starting/stopping NetGuard via broadcasts.","compatiblePackages":[{"name":"eu.faircode.netguard","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove debugging detection","description":"Removes the USB and wireless debugging checks.","compatiblePackages":[{"name":"com.scb.phone","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":["4.29"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass root checks","description":"Removes the restriction to use the app with root permissions or on a custom ROM.","compatiblePackages":[{"name":"it.ipzs.cieid","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show deleted messages","description":"Shows deleted chat messages behind a clickable spoiler.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Auto claim channel points","description":"Automatically claim Channel Points.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block audio ads","description":"Blocks audio ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block embedded ads","description":"Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block video ads","description":"Blocks video ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds settings menu to Twitch.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Debug mode","description":"Enables Twitch\u0027s internal debugging mode.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable switching emoji to sticker","description":"Disables switching from emoji to sticker search mode in message input field.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable typing indicator","description":"Disables the indicator while typing a message.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide inbox ads","description":"Hides ads in inbox.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides most of the ads across the app.","compatiblePackages":[{"name":"com.myfitnesspal.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide story ads","description":"Hides the ads in the Facebook app stories.","compatiblePackages":[{"name":"com.facebook.katana","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove badge tab","description":"Removes the badge tab from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove notification badge","description":"Removes the red notification badge from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":["10.1.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timeline ads","description":"Removes ads from the timeline.","compatiblePackages":[{"name":"com.instagram.android","versions":["275.0.0.27.98"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove file size limit","description":"Allows opening files larger than 2 MB in the text editor.","compatiblePackages":[{"name":"pl.solidexplorer2","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Adds options to remove general ads.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Video ads","description":"Adds an option to remove ads in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Spoof device dimensions","description":"Adds an option to spoof the device dimensions which unlocks higher video qualities if they aren\u0027t available on the device.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable zoom haptics","description":"Adds an option to disable haptics when zooming.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass URL redirects","description":"Adds an option to bypass URL redirects and open the original URL directly.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Open links externally","description":"Adds an option to always open links in your browser instead of in the in-app-browser.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove tracking query parameter","description":"Adds an option to remove the tracking info from links you share.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Always repeat","description":"Adds an option to always repeat videos when they end.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Announcements","description":"Adds an option to show announcements from ReVanced on app startup.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Client spoof","description":"Adds options to spoof the client to allow video playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable debugging","description":"Adds options for debugging.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Unlocks options for picture-in-picture and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Seekbar tapping","description":"Adds an option to enable tap-to-seek on the seekbar of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable slide to seek","description":"Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable precise seeking gesture","description":"Adds an option to disable precise seeking when swiping up on the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Copy video URL","description":"Adds options to display buttons in the video player to copy video URLs.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"External downloads","description":"Adds support to download and save YouTube videos using an external downloader app.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove viewer discretion dialog","description":"Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds options to enable and configure volume and brightness swipe controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove player controls background","description":"Removes the dark background surrounding the video player controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Custom player overlay opacity","description":"Adds an option to change the opacity of the video player background when player controls are visible.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old seekbar thumbnails","description":"Adds an option to restore the old seekbar thumbnails that appear above the seekbar while seeking instead of fullscreen thumbnails.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof app version","description":"Adds an option to trick YouTube into thinking you are running an older version of the app. This can be used to restore old UI elements and features.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Return YouTube Dislike","description":"Adds an option to show the dislike count of videos using the Return YouTube Dislike API.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Adds options to hide menu items that appear when pressing the gear icon in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Adds an option to hide info cards that creators add in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Adds an option to hide the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Adds an option to hide suggested video cards at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Adds options to hide components related to comments.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable rolling number animations","description":"Adds an option to disable rolling number animations of video view count, user likes, and upload time.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable fullscreen ambient mode","description":"Adds an option to disable the ambient mode when in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide floating microphone button","description":"Adds an option to hide the floating microphone button when searching.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide layout components","description":"Adds options to hide general layout components.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Adds options to hide components related to YouTube Shorts.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide \u0027Load more\u0027 button","description":"Adds an option to hide the button under videos that loads similar videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide crowdfunding box","description":"Adds an option to hide the crowdfunding box between the player and video description.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Adds an option to hide the timestamp in the bottom left of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide breaking news shelf","description":"Adds an option to hide the breaking news shelf on the homepage tab.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable suggested video end screen","description":"Adds an option to disable the suggested video end screen at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide album cards","description":"Adds an option to hide album cards below artist descriptions.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide filter bar","description":"Adds options to hide the category bar at the top of video feeds.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom branding","description":"Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"appName","default":"YouTube ReVanced","values":{"YouTube ReVanced":"YouTube ReVanced","YT ReVanced":"YT ReVanced","YT":"YT","YouTube":"YouTube"},"title":"App name","description":"The name of the app.","required":false},{"key":"iconPath","default":"ReVanced*Logo","values":{"ReVanced Logo":"ReVanced*Logo"},"title":"App icon","description":"The path to a folder containing the following folders:\n\n- mipmap-xxxhdpi\n- mipmap-xxhdpi\n- mipmap-xhdpi\n- mipmap-hdpi\n- mipmap-mdpi\n\nEach of these folders has to have the following files:\n\n- adaptiveproduct_youtube_background_color_108.png\n- adaptiveproduct_youtube_foreground_color_108.png\n- ic_launcher.png\n- ic_launcher_round.png","required":false}]},{"name":"Change header","description":"Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"header","default":"ReVanced (borderless logo)","values":{"YouTube":"yt_wordmark_header","YouTube Premium":"yt_premium_wordmark_header","ReVanced":"ReVanced","ReVanced (borderless logo)":"ReVanced (borderless logo)"},"title":"Header","description":"Either a header name or a path to a custom header folder to use in the top bar.\nThe path to a folder must contain one or more of the following folders matching the DPI of your device:\n\n- drawable-xxxhdpi\n- drawable-xxhdpi\n- drawable-xhdpi\n- drawable-mdpi\n- drawable-hdpi\n\nThese folders must contain the following files:\n\n- yt_wordmark_header_light.png\n- yt_wordmark_header_dark.png","required":true}]},{"name":"Hide player buttons","description":"Adds an option to hide the previous and next buttons in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Navigation buttons","description":"Adds options to hide and change navigation buttons (such as the Shorts button).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide video action buttons","description":"Adds options to hide action buttons (such as the Download button) under videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide cast button","description":"Adds an option to hide the cast button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Adds an option to hide the captions button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide autoplay button","description":"Adds an option to hide the autoplay button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable tablet layout","description":"Adds an option to spoof the device form factor to a tablet which enables the tablet layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable resuming Shorts on startup","description":"Adds an option to disable the Shorts player from resuming on app startup when Shorts were last being watched.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change start page","description":"Adds an option to set which page the app opens in instead of the homepage.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Theme","description":"Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[{"key":"darkThemeBackgroundColor","default":"@android:color/black","values":{"Amoled black":"@android:color/black","Material You":"@android:color/system_neutral1_900","Classic (old YouTube)":"#FF212121","Catppuccin (Mocha)":"#FF181825","Dark pink":"#FF290025","Dark blue":"#FF001029","Dark green":"#FF002905","Dark yellow":"#FF282900","Dark orange":"#FF291800","Dark red":"#FF290000"},"title":"Dark theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false},{"key":"lightThemeBackgroundColor","default":"@android:color/white","values":{"White":"@android:color/white","Material You":"@android:color/system_neutral1_50","Catppuccin (Latte)":"#FFE6E9EF","Light pink":"#FFFCCFF3","Light blue":"#FFD1E0FF","Light green":"#FFCCFFCC","Light yellow":"#FFFDFFCC","Light orange":"#FFFFE6CC","Light red":"#FFFFD6D6"},"title":"Light theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false}]},{"name":"Disable auto captions","description":"Adds an option to disable captions from being automatically enabled.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Wide searchbar","description":"Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Adds an option to enable the tablet mini player layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Alternative thumbnails","description":"Adds options to replace video thumbnails using the DeArrow API or image captures from the video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable player popup panels","description":"Adds an option to disable panels (such as live chat) from opening automatically.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds an option to remember the last video quality selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"HDR auto brightness","description":"Adds an option to make the brightness of HDR videos follow the system default.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds options to customize available playback speeds and to remember the last playback speed selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old video quality menu","description":"Adds an option to restore the old video quality menu with specific video resolution options.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable Tumblr Live","description":"Disable the Tumblr Live tab button and dashboard carousel.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable gift message popup","description":"Disables the popup suggesting to buy TumblrMart items for other people.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable in-app update","description":"Disables the in-app update check and update prompt.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable blog notification reminder","description":"Disables the reminder to enable notifications for blogs you visit.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable dashboard ads","description":"Disables ads in the dashboard.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock plus","description":null,"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide update popup","description":"Prevents the update popup from showing up.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device ID","description":"Spoofs device ID to mitigate manual bans by developers.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Dynamic color","description":"Replaces the default X (Formerly Twitter) Blue with the user\u0027s Material You palette.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide recommended users","description":null,"compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides ads.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock downloads","description":"Unlocks the ability to download any video.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide view count","description":"Hides the view count of Posts.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Custom theme","description":"Applies a custom theme.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"backgroundColor","default":"@android:color/black","values":null,"title":"Primary background color","description":"The background color. Can be a hex color or a resource reference.","required":true},{"key":"backgroundColorSecondary","default":"#ff282828","values":null,"title":"Secondary background color","description":"The secondary background color. (e.g. search box, artist \u0026 podcast). Can be a hex color or a resource reference.","required":true},{"key":"accentColor","default":"#ff1ed760","values":null,"title":"Accent color","description":"The accent color (\u0027Spotify green\u0027 by default). Can be a hex color or a resource reference.","required":true},{"key":"accentColorPressed","default":"#ff169c46","values":null,"title":"Pressed dark theme accent color","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":true}]},{"name":"Enable on demand","description":"Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.","compatiblePackages":[{"name":"com.spotify.lite","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide premium navbar","description":"Removes the premium tab from the navbar.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Change package name","description":"Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"packageName","default":"Default","values":{"Default":"Default"},"title":"Package name","description":"The name of the package to rename the app to.","required":true}]},{"name":"Enable Android debugging","description":"Enables Android debugging capabilities. This can slow down the app.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Override certificate pinning","description":"Overrides certificate pinning, allowing to inspect traffic via a proxy.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Predictive back gesture","description":"Enables the predictive back gesture introduced on Android 13.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove screenshot restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Remove screen capture restriction","description":"Removes the restriction of capturing audio from apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Spoof SIM country","description":"Spoofs country information returned by the SIM card provider.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"networkCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Network ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false},{"key":"simCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Sim ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false}]},{"name":"Spoof Wi-Fi connection","description":"Spoofs an existing Wi-Fi connection.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Sanitize sharing links","description":"Removes (tracking) query parameters from the URLs when sharing links.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"free.reddit.news","versions":null},{"name":"reddit.news","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"dbrady://relay\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"infinity://localhost\".","required":true}]},{"name":"Unlock subscription","description":"Unlocks the subscription feature but requires a custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"o.o.joey","versions":null},{"name":"o.o.joey.pro","versions":null},{"name":"o.o.joey.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"https://127.0.0.1:65023/authorize_callback\".","required":true}]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"o.o.joey","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.rubenmayayo.reddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://rubenmayayo.com\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"me.ccrama.redditslide","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://www.ccrama.me\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.andrewshu.android.reddit","versions":null},{"name":"com.andrewshu.android.redditdonation","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"redditisfun://auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.onelouder.baconreader","versions":null},{"name":"com.onelouder.baconreader.premium","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://baconreader.com/auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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\".","required":true}]},{"name":"Fix /s/ links","description":"Fixes the issue where /s/ links do not work.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Disable Sync for Lemmy bottom sheet","description":"Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":["v23.06.30-13:39"]},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable screenshot popup","description":"Disables the popup that shows up when taking a screenshot.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium Reddit icons","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.awedea.nyx","versions":["2.2.7"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof signature","description":"Spoofs the signature of the app.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","compatiblePackages":[{"name":"com.ticktick.task","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Music video ads","description":"Removes ads in the music player.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Bypass certificate checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Permanent repeat","description":"Permanently remember your repeating preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Permanent shuffle","description":"Permanently remember your shuffle preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Codecs unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Exclusive audio playback","description":"Enables the option to play audio without video.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove upgrade button","description":"Removes the upgrade tab from the pivot bar.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Compact header","description":"Hides the music category bar at the top of the homepage.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Hide get premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback music","description":"Enables minimized playback on Kids music.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Background play","description":"Enables playing music in the background.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"jp.pxv.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show on lockscreen","description":"Shows student id and student ticket on lockscreen.","compatiblePackages":[{"name":"de.tudortmund.app","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Feed filter","description":"Removes ads, livestreams, stories, image videos and videos with a specific amount of views or likes from the feed.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SIM spoof","description":"Spoofs the information which is retrieved from the SIM card.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable login requirement","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Fix Google login","description":"Allows logging in with a Google account.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds ReVanced settings to TikTok.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show seekbar","description":"Shows progress bar for all video.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Downloads","description":"Removes download restrictions and changes the default path to download to.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Enables the playback speed option for all videos and retains the speed configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember clear display","description":"Remembers the clear display configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Promo code unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","compatiblePackages":[{"name":"de.dwd.warnapp","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable subscription suggestions","description":null,"compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock subscription features","description":"Unlocks \"Routes\", \"Matched Runs\" and \"Segment Efforts\".","compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Pro unlock","description":null,"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bka.serviceportal","versions":null}],"use":true,"requiresIntegrations":false,"options":[]}] \ No newline at end of file From de3f2910fca056bbb544511496ba1beef03b5dde Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 13 Feb 2024 02:54:40 +0100 Subject: [PATCH 04/52] build: Bump dependencies --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8da2c1cb..918f83c6 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] revanced-patcher = "19.2.0" -smali = "3.0.3" +smali = "3.0.4" guava = "33.0.0-jre" gson = "2.10.1" binary-compatibility-validator = "0.13.2" From f80feb743e3e08f8cce697ac4a747783c176246a Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 13 Feb 2024 02:55:07 +0100 Subject: [PATCH 05/52] chore: Add `.editorconfig` --- .editorconfig | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..2d6d258f --- /dev/null +++ b/.editorconfig @@ -0,0 +1,3 @@ +[*.{kt,kts}] +ktlint_code_style = intellij_idea +ktlint_standard_no-wildcard-imports = disabled \ No newline at end of file From a430d3c5a1291e1ef7fb198688bbe52bbcdc45e0 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 13 Feb 2024 02:58:24 +0100 Subject: [PATCH 06/52] chore: Remove `dummy` subproject It is not necessary anymore --- build.gradle.kts | 5 +---- dummy/build.gradle.kts | 9 --------- dummy/src/main/java/android/os/Environment.java | 9 --------- settings.gradle.kts | 2 -- 4 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 dummy/build.gradle.kts delete mode 100644 dummy/src/main/java/android/os/Environment.java diff --git a/build.gradle.kts b/build.gradle.kts index 9c0f5574..5e9743b5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -22,9 +22,6 @@ dependencies { implementation(libs.guava) // Used in JsonGenerator. implementation(libs.gson) - - // A dependency to the Android library unfortunately fails the build, which is why this is required. - compileOnly(project("dummy")) } kotlin { @@ -120,4 +117,4 @@ publishing { } } } -} \ No newline at end of file +} diff --git a/dummy/build.gradle.kts b/dummy/build.gradle.kts deleted file mode 100644 index 04b0d269..00000000 --- a/dummy/build.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -plugins { - id("java") -} - -java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(11)) - } -} \ No newline at end of file diff --git a/dummy/src/main/java/android/os/Environment.java b/dummy/src/main/java/android/os/Environment.java deleted file mode 100644 index 5d58fc31..00000000 --- a/dummy/src/main/java/android/os/Environment.java +++ /dev/null @@ -1,9 +0,0 @@ -package android.os; - -import java.io.File; - -public final class Environment { - public static File getExternalStorageDirectory() { - throw new UnsupportedOperationException("Stub"); - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index f0eef03d..432b2001 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,3 @@ -include("dummy") - rootProject.name = "revanced-patches" buildCache { From 8dc0133c0b7e5b167eb8d6ea45d4d9616c49348a Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 13 Feb 2024 03:27:03 +0100 Subject: [PATCH 07/52] chore: Fix `ReplaceWith` of `Deprecated` annotation --- .../integrations/BaseIntegrationsPatch.kt | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt index 9cf84495..eb7f7e87 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt @@ -11,23 +11,25 @@ import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method abstract class BaseIntegrationsPatch( - private val hooks: Set + private val hooks: Set, ) : BytecodePatch(hooks) { @Deprecated( "Use the constructor without the integrationsDescriptor parameter", - ReplaceWith("AbstractIntegrationsPatch(hooks)") + ReplaceWith("BaseIntegrationsPatch(hooks)"), ) @Suppress("UNUSED_PARAMETER") constructor( integrationsDescriptor: String, - hooks: Set + hooks: Set, ) : this(hooks) override fun execute(context: BytecodeContext) { - if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) throw PatchException( - "Integrations have not been merged yet. This patch can not succeed without merging the integrations." - ) + if (context.findClass(INTEGRATIONS_CLASS_DESCRIPTOR) == null) { + throw PatchException( + "Integrations have not been merged yet. This patch can not succeed without merging the integrations.", + ) + } hooks.forEach { hook -> hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR) @@ -47,14 +49,14 @@ abstract class BaseIntegrationsPatch( opcodes: Iterable? = null, strings: Iterable? = null, customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null, - private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {} + private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {}, ) : MethodFingerprint( returnType, accessFlags, parameters, opcodes, strings, - customFingerprint + customFingerprint, ) { fun invoke(integrationsDescriptor: String) { result?.mutableMethod?.let { method -> @@ -63,7 +65,7 @@ abstract class BaseIntegrationsPatch( method.addInstruction( 0, "sput-object v$contextRegister, " + - "$integrationsDescriptor->context:Landroid/content/Context;" + "$integrationsDescriptor->context:Landroid/content/Context;", ) } ?: throw PatchException("Could not find hook target fingerprint.") } @@ -76,4 +78,4 @@ abstract class BaseIntegrationsPatch( private companion object { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/shared/Utils;" } -} \ No newline at end of file +} From 16d8d26f9af6578cc40722a733578ea0dc800cbf Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 14 Feb 2024 02:41:21 +0100 Subject: [PATCH 08/52] build: Bump Gradle --- gradle/wrapper/gradle-wrapper.properties | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index db8c3baa..3f203e9f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,8 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=9d926787066a081739e8200858338b4a69e837c3a821a33aca9db09dd4a41026 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip -networkTimeout=10000 -validateDistributionUrl=true +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip +distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists +zipStorePath=wrapper/dist \ No newline at end of file From e86389e543cfbd977cfa6fe57496ff81e992423b Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 14 Feb 2024 02:44:25 +0100 Subject: [PATCH 09/52] build: Bump dependencies --- gradle/libs.versions.toml | 2 +- package-lock.json | 280 ++++++++++++++++++++++++++++++-------- package.json | 2 +- 3 files changed, 228 insertions(+), 56 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 918f83c6..2b26096f 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,7 +3,7 @@ revanced-patcher = "19.2.0" smali = "3.0.4" guava = "33.0.0-jre" gson = "2.10.1" -binary-compatibility-validator = "0.13.2" +binary-compatibility-validator = "0.14.0" [libraries] revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" } diff --git a/package-lock.json b/package-lock.json index 29e79ed2..415c2d42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "gradle-semantic-release-plugin": "^1.9.1", - "semantic-release": "^23.0.0" + "semantic-release": "^23.0.2" } }, "node_modules/@babel/code-frame": { @@ -326,9 +326,9 @@ } }, "node_modules/@octokit/request": { - "version": "8.1.6", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", - "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.2.0.tgz", + "integrity": "sha512-exPif6x5uwLqv1N1irkLG1zZNJkOtj8bZxuVHd71U5Ftuxf2wGNvAJyNBcPbPC+EBzwYEbBDdSFb8EPcjpYxPQ==", "dev": true, "dependencies": { "@octokit/endpoint": "^9.0.0", @@ -564,6 +564,26 @@ "node": ">= 16" } }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/marked-terminal": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.2.0.tgz", + "integrity": "sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==", + "dev": true, + "dependencies": { + "ansi-escapes": "^6.2.0", + "cardinal": "^2.1.1", + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "node-emoji": "^2.1.3", + "supports-hyperlinks": "^3.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <12" + } + }, "node_modules/@saithodev/semantic-release-backmerge/node_modules/mimic-fn": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", @@ -1195,9 +1215,9 @@ } }, "node_modules/@sindresorhus/merge-streams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", - "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.2.0.tgz", + "integrity": "sha512-UTce8mUwUW0RikMb/eseJ7ys0BRkZVFB86orHzrfW12ZmFtym5zua8joZ4L7okH2dDFHkcFjqnZ5GocWBXOFtA==", "dev": true, "engines": { "node": ">=18" @@ -1282,6 +1302,12 @@ "integrity": "sha512-QXu7BPrP29VllRxH8GwB7x5iX5qWKAAMLqKQGWTeLWVlNHNOpVMJ91dsxQAIWXpjuW5wqvxu3Jd/nRjrJ+0pqg==", "dev": true }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1376,6 +1402,81 @@ "node": ">=6" } }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/cli-table3": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", @@ -1818,9 +1919,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" @@ -1888,9 +1989,9 @@ } }, "node_modules/fastq": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", - "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2052,12 +2153,12 @@ } }, "node_modules/globby": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", - "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", "dev": true, "dependencies": { - "@sindresorhus/merge-streams": "^1.0.0", + "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.2", "ignore": "^5.2.4", "path-type": "^5.0.0", @@ -2142,9 +2243,9 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", + "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", "dev": true, "dependencies": { "function-bind": "^1.1.2" @@ -2153,6 +2254,15 @@ "node": ">= 0.4" } }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/hook-std": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", @@ -2178,9 +2288,9 @@ } }, "node_modules/http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.1.tgz", + "integrity": "sha512-My1KCEPs6A0hb4qCVzYp8iEvA8j8YqcvXLZZH8C9OFuTYpYjHE7N2dtG3mRl1HMD4+VGXpF3XcDVcxGBT7yDZQ==", "dev": true, "dependencies": { "agent-base": "^7.1.0", @@ -2191,9 +2301,9 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.3.tgz", + "integrity": "sha512-kCnwztfX0KZJSLOBrcL0emLeFako55NWMovvyPP2AjsghNk9RB1yjSI+jVumPHYZsNXegNoqupSW9IY3afSH8w==", "dev": true, "dependencies": { "agent-base": "^7.0.2", @@ -2213,9 +2323,9 @@ } }, "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" @@ -2629,9 +2739,9 @@ } }, "node_modules/marked": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/marked/-/marked-11.1.1.tgz", - "integrity": "sha512-EgxRjgK9axsQuUa/oKMx5DEY8oXpKJfk61rT5iY3aRlgU6QJtUcxU5OAymdhCvWvhYcd9FKmO5eQoX8m9VGJXg==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.0.tgz", + "integrity": "sha512-Vkwtq9rLqXryZnWaQc86+FHLC6tr/fycMfYAhiOIXkrNmeGAyhSxjqu0Rs1i0bBqw5u0S7+lV9fdH2ZSVaoa0w==", "dev": true, "bin": { "marked": "bin/marked.js" @@ -2641,14 +2751,14 @@ } }, "node_modules/marked-terminal": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.2.0.tgz", - "integrity": "sha512-ubWhwcBFHnXsjYNsu+Wndpg0zhY4CahSpPlA70PlO0rR9r2sZpkyU+rkCsOWH+KMEkx847UpALON+HWgxowFtw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.0.0.tgz", + "integrity": "sha512-sNEx8nn9Ktcm6pL0TnRz8tnXq/mSS0Q1FRSwJOAqw4lAB4l49UeDf85Gm1n9RPFm5qurCPjwi1StAQT2XExhZw==", "dev": true, "dependencies": { "ansi-escapes": "^6.2.0", - "cardinal": "^2.1.1", "chalk": "^5.3.0", + "cli-highlight": "^2.1.11", "cli-table3": "^0.6.3", "node-emoji": "^2.1.3", "supports-hyperlinks": "^3.0.0" @@ -2657,7 +2767,7 @@ "node": ">=16.0.0" }, "peerDependencies": { - "marked": ">=1 <12" + "marked": ">=1 <13" } }, "node_modules/meow": { @@ -2739,6 +2849,17 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, "node_modules/neo-async": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", @@ -5551,6 +5672,15 @@ "inBundle": true, "license": "ISC" }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -5695,6 +5825,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, "node_modules/parsimmon": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz", @@ -5860,9 +6011,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz", - "integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz", + "integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==", "dev": true, "engines": { "node": ">=16" @@ -5889,9 +6040,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.10.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz", - "integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==", + "version": "4.10.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.2.tgz", + "integrity": "sha512-anpAG63wSpdEbLwOqH8L84urkL6PiVIov3EMmgIhhThevh9aiMQov+6Btx0wldNcvm4wV+e2/Rt1QdDwKHFbHw==", "dev": true, "engines": { "node": ">=16" @@ -5994,9 +6145,9 @@ "dev": true }, "node_modules/semantic-release": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.0.tgz", - "integrity": "sha512-Jz7jEWO2igTtske112gC4PPE2whCMVrsgxUPG3/SZI7VE357suIUZFlJd1Yu0g2I6RPc2HxNEfUg7KhmDTjwqg==", + "version": "23.0.2", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.2.tgz", + "integrity": "sha512-OnVYJ6Xgzwe1x8MKswba7RU9+5djS1MWRTrTn5qsq3xZYpslroZkV9Pt0dA2YcIuieeuSZWJhn+yUWoBUHO5Fw==", "dev": true, "dependencies": { "@semantic-release/commit-analyzer": "^11.0.0", @@ -6017,8 +6168,8 @@ "hosted-git-info": "^7.0.0", "import-from-esm": "^1.3.1", "lodash-es": "^4.17.21", - "marked": "^11.0.0", - "marked-terminal": "^6.0.0", + "marked": "^12.0.0", + "marked-terminal": "^7.0.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", "p-reduce": "^3.0.0", @@ -6247,9 +6398,9 @@ } }, "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -6481,9 +6632,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", "dev": true }, "node_modules/split2": { @@ -6655,6 +6806,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", diff --git a/package.json b/package.json index 31010700..63762667 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,6 @@ "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", "gradle-semantic-release-plugin": "^1.9.1", - "semantic-release": "^23.0.0" + "semantic-release": "^23.0.2" } } From 3b8bc08d4ed3a3a0f96d2f476e5059840b9f9d9b Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 20 Feb 2024 22:30:26 +0100 Subject: [PATCH 10/52] feat(YouTube - Change header): Improve patch option description --- .../branding/header/ChangeHeaderPatch.kt | 107 ++++++++++-------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt index 6f1e76a0..f02b982d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -15,62 +15,69 @@ import java.io.File name = "Change header", description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.", compatiblePackages = [ - CompatiblePackage("com.google.android.youtube") + CompatiblePackage("com.google.android.youtube"), ], - use = false + use = false, ) @Suppress("unused") object ChangeHeaderPatch : ResourcePatch() { - private const val HEADER_NAME = "yt_wordmark_header" - private const val PREMIUM_HEADER_NAME = "yt_premium_wordmark_header" - private const val REVANCED_HEADER_NAME = "ReVanced" - private const val REVANCED_BORDERLESS_HEADER_NAME = "ReVanced (borderless logo)" + private const val HEADER_FILE_NAME = "yt_wordmark_header" + private const val PREMIUM_HEADER_FILE_NAME = "yt_premium_wordmark_header" - private val targetResourceDirectoryNames = arrayOf( - "xxxhdpi", - "xxhdpi", - "xhdpi", - "mdpi", - "hdpi", - ).map { dpi -> - "drawable-$dpi" - } + private const val HEADER_OPTION = "header*" + private const val PREMIUM_HEADER_OPTION = "premium*header" + private const val REVANCED_HEADER_OPTION = "revanced*" + private const val REVANCED_BORDERLESS_HEADER_OPTION = "revanced*borderless" + + private val targetResourceDirectoryNames = mapOf( + "xxxhdpi" to "512px x 192px", + "xxhdpi" to "387px x 144px", + "xhdpi" to "258px x 96px", + "hdpi" to "194px x 72px", + "mdpi" to "129px x 48px", + ).map { (dpi, dim) -> + "drawable-$dpi" to dim + }.toMap() private val variants = arrayOf("light", "dark") private val header by stringPatchOption( key = "header", - default = REVANCED_BORDERLESS_HEADER_NAME, + default = REVANCED_BORDERLESS_HEADER_OPTION, values = mapOf( - "YouTube" to HEADER_NAME, - "YouTube Premium" to PREMIUM_HEADER_NAME, - "ReVanced" to REVANCED_HEADER_NAME, - "ReVanced (borderless logo)" to REVANCED_BORDERLESS_HEADER_NAME, + "YouTube" to HEADER_OPTION, + "YouTube Premium" to PREMIUM_HEADER_OPTION, + "ReVanced" to REVANCED_HEADER_OPTION, + "ReVanced (borderless logo)" to REVANCED_BORDERLESS_HEADER_OPTION, ), title = "Header", description = """ - Either a header name or a path to a custom header folder to use in the top bar. - The path to a folder must contain one or more of the following folders matching the DPI of your device: + The header to apply to the app. + + If a path to a folder is provided, the folder must contain one or more of the following folders, depending on the DPI of the device: + + ${targetResourceDirectoryNames.keys.joinToString("\n") { "- $it" }} + + Each of the folders must contain all of the following files: + + ${variants.joinToString("\n") { variant -> "- ${HEADER_FILE_NAME}_$variant.png" }} - ${targetResourceDirectoryNames.joinToString("\n") { "- $it" }} - - These folders must contain the following files: - - ${variants.joinToString("\n") { variant -> "- ${HEADER_NAME}_$variant.png" }} + The image dimensions must be as follows: + ${targetResourceDirectoryNames.map { (dpi, dim) -> "- $dpi: $dim" }.joinToString("\n")} """.trimIndentMultiline(), required = true, ) override fun execute(context: ResourceContext) { // The directories to copy the header to. - val targetResourceDirectories = targetResourceDirectoryNames.mapNotNull { + val targetResourceDirectories = targetResourceDirectoryNames.keys.mapNotNull { context["res"].resolve(it).takeIf(File::exists) } // The files to replace in the target directories. - val targetResourceFiles = targetResourceDirectoryNames.map { directoryName -> + val targetResourceFiles = targetResourceDirectoryNames.keys.map { directoryName -> ResourceGroup( directoryName, - *variants.map { variant -> "${HEADER_NAME}_$variant.png" }.toTypedArray() + *variants.map { variant -> "${HEADER_FILE_NAME}_$variant.png" }.toTypedArray(), ) } @@ -89,8 +96,8 @@ object ChangeHeaderPatch : ResourcePatch() { } // Functions to overwrite the header to the different variants. - val toPremium = { overwriteFromTo(PREMIUM_HEADER_NAME, HEADER_NAME) } - val toHeader = { overwriteFromTo(HEADER_NAME, PREMIUM_HEADER_NAME) } + val toPremium = { overwriteFromTo(PREMIUM_HEADER_FILE_NAME, HEADER_FILE_NAME) } + val toHeader = { overwriteFromTo(HEADER_FILE_NAME, PREMIUM_HEADER_FILE_NAME) } val toReVanced = { // Copy the ReVanced header to the resource directories. targetResourceFiles.forEach { context.copyResources("change-header/revanced", it) } @@ -106,32 +113,38 @@ object ChangeHeaderPatch : ResourcePatch() { toHeader() } val toCustom = { - var copiedReplacementImages = false - // For all the resource groups in the custom header folder, copy them to the resource directories. - File(header!!).listFiles { file -> file.isDirectory }?.forEach { folder -> - val targetDirectory = context["res"].resolve(folder.name) - // Skip if the target directory (DPI) doesn't exist. - if (!targetDirectory.exists()) return@forEach + val sourceFolders = File(header!!).listFiles { file -> file.isDirectory } + ?: throw PatchException("The provided path is not a directory: $header") - folder.listFiles { file -> file.isFile }?.forEach { - val targetResourceFile = targetDirectory.resolve(it.name) + var copiedFiles = false - it.copyTo(targetResourceFile, true) - copiedReplacementImages = true + // For each source folder, copy the files to the target resource directories. + sourceFolders.forEach { dpiSourceFolder -> + val targetDpiFolder = context["res"].resolve(dpiSourceFolder.name) + if (!targetDpiFolder.exists()) return@forEach + + val imgSourceFiles = dpiSourceFolder.listFiles { file -> file.isFile }!! + imgSourceFiles.forEach { imgSourceFile -> + val imgTargetFile = targetDpiFolder.resolve(imgSourceFile.name) + imgSourceFile.copyTo(imgTargetFile, true) + + copiedFiles = true } } - if (!copiedReplacementImages) throw PatchException("Could not find any custom images resources in directory: $header") + if (!copiedFiles) { + throw PatchException("No header files were copied from the provided path: $header.") + } // Overwrite the premium with the custom header as well. toHeader() } when (header) { - HEADER_NAME -> toHeader - PREMIUM_HEADER_NAME -> toPremium - REVANCED_HEADER_NAME -> toReVanced - REVANCED_BORDERLESS_HEADER_NAME -> toReVancedBorderless + HEADER_OPTION -> toHeader + PREMIUM_HEADER_OPTION -> toPremium + REVANCED_HEADER_OPTION -> toReVanced + REVANCED_BORDERLESS_HEADER_OPTION -> toReVancedBorderless else -> toCustom }() } From e27f56c8a34d41167b290f47280276c1c6003876 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 20 Feb 2024 22:30:50 +0100 Subject: [PATCH 11/52] feat(YouTube - Custom branding): Improve patch option description --- .../layout/branding/CustomBrandingPatch.kt | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt index 587e0d4e..19aa116b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt @@ -15,9 +15,9 @@ import java.nio.file.Files name = "Custom branding", description = "Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.", compatiblePackages = [ - CompatiblePackage("com.google.android.youtube") + CompatiblePackage("com.google.android.youtube"), ], - use = false + use = false, ) @Suppress("unused") object CustomBrandingPatch : ResourcePatch() { @@ -28,7 +28,7 @@ object CustomBrandingPatch : ResourcePatch() { "adaptiveproduct_youtube_background_color_108", "adaptiveproduct_youtube_foreground_color_108", "ic_launcher", - "ic_launcher_round" + "ic_launcher_round", ).map { "$it.png" }.toTypedArray() private val mipmapDirectories = arrayOf( @@ -36,7 +36,7 @@ object CustomBrandingPatch : ResourcePatch() { "xxhdpi", "xhdpi", "hdpi", - "mdpi" + "mdpi", ).map { "mipmap-$it" } private var appName by stringPatchOption( @@ -49,7 +49,7 @@ object CustomBrandingPatch : ResourcePatch() { "YouTube" to "YouTube", ), title = "App name", - description = "The name of the app." + description = "The name of the app.", ) private var icon by stringPatchOption( @@ -58,14 +58,16 @@ object CustomBrandingPatch : ResourcePatch() { values = mapOf("ReVanced Logo" to REVANCED_ICON), title = "App icon", description = """ - The path to a folder containing the following folders: + The icon to apply to the app. + + If a path to a folder is provided, the folder must contain the following folders: ${mipmapDirectories.joinToString("\n") { "- $it" }} - Each of these folders has to have the following files: + Each of these folders must contain the following files: ${iconResourceFileNames.joinToString("\n") { "- $it" }} - """.trimIndentMultiline() + """.trimIndentMultiline(), ) override fun execute(context: ResourceContext) { @@ -73,7 +75,8 @@ object CustomBrandingPatch : ResourcePatch() { // Change the app icon. mipmapDirectories.map { directory -> ResourceGroup( - directory, *iconResourceFileNames + directory, + *iconResourceFileNames, ) }.let { resourceGroups -> if (icon != REVANCED_ICON) { @@ -87,11 +90,13 @@ object CustomBrandingPatch : ResourcePatch() { group.resources.forEach { iconFileName -> Files.write( toDirectory.resolve(iconFileName).toPath(), - fromDirectory.resolve(iconFileName).readBytes() + fromDirectory.resolve(iconFileName).readBytes(), ) } } - } else resourceGroups.forEach { context.copyResources("custom-branding", it) } + } else { + resourceGroups.forEach { context.copyResources("custom-branding", it) } + } } } @@ -102,8 +107,8 @@ object CustomBrandingPatch : ResourcePatch() { manifest.readText() .replace( "android:label=\"@string/application_name", - "android:label=\"$name" - ) + "android:label=\"$name", + ), ) } } From 2c438e414d2907f0844fa72ec35239c29aadadde Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Tue, 20 Feb 2024 21:43:11 +0000 Subject: [PATCH 12/52] chore(release): 4.3.0-dev.3 [skip ci] # [4.3.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.2...v4.3.0-dev.3) (2024-02-20) ### Features * **YouTube - Change header:** Improve patch option description ([3b8bc08](https://github.com/ReVanced/revanced-patches/commit/3b8bc08d4ed3a3a0f96d2f476e5059840b9f9d9b)) * **YouTube - Custom branding:** Improve patch option description ([e27f56c](https://github.com/ReVanced/revanced-patches/commit/e27f56c8a34d41167b290f47280276c1c6003876)) --- CHANGELOG.md | 8 ++++++++ gradle.properties | 2 +- patches.json | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18ae9af2..7794fcee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,11 @@ +# [4.3.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.2...v4.3.0-dev.3) (2024-02-20) + + +### Features + +* **YouTube - Change header:** Improve patch option description ([3b8bc08](https://github.com/ReVanced/revanced-patches/commit/3b8bc08d4ed3a3a0f96d2f476e5059840b9f9d9b)) +* **YouTube - Custom branding:** Improve patch option description ([e27f56c](https://github.com/ReVanced/revanced-patches/commit/e27f56c8a34d41167b290f47280276c1c6003876)) + # [4.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.1...v4.3.0-dev.2) (2024-02-09) diff --git a/gradle.properties b/gradle.properties index 3153271a..839651dc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.2 +version = 4.3.0-dev.3 diff --git a/patches.json b/patches.json index cbc74ff6..656ae579 100644 --- a/patches.json +++ b/patches.json @@ -1 +1 @@ -[{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":["2.2 build 016"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove device restrictions","description":"Removes restrictions from using the app on any device. Requires mounting patched app over original.","compatiblePackages":[{"name":"com.google.android.apps.recorder","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove bootloader detection","description":"Removes the check for an unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable mandatory login","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove broadcasts restriction","description":"Enables starting/stopping NetGuard via broadcasts.","compatiblePackages":[{"name":"eu.faircode.netguard","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove debugging detection","description":"Removes the USB and wireless debugging checks.","compatiblePackages":[{"name":"com.scb.phone","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":["4.29"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass root checks","description":"Removes the restriction to use the app with root permissions or on a custom ROM.","compatiblePackages":[{"name":"it.ipzs.cieid","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show deleted messages","description":"Shows deleted chat messages behind a clickable spoiler.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Auto claim channel points","description":"Automatically claim Channel Points.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block audio ads","description":"Blocks audio ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block embedded ads","description":"Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block video ads","description":"Blocks video ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds settings menu to Twitch.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Debug mode","description":"Enables Twitch\u0027s internal debugging mode.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable switching emoji to sticker","description":"Disables switching from emoji to sticker search mode in message input field.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable typing indicator","description":"Disables the indicator while typing a message.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide inbox ads","description":"Hides ads in inbox.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides most of the ads across the app.","compatiblePackages":[{"name":"com.myfitnesspal.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide story ads","description":"Hides the ads in the Facebook app stories.","compatiblePackages":[{"name":"com.facebook.katana","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove badge tab","description":"Removes the badge tab from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove notification badge","description":"Removes the red notification badge from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":["10.1.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timeline ads","description":"Removes ads from the timeline.","compatiblePackages":[{"name":"com.instagram.android","versions":["275.0.0.27.98"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove file size limit","description":"Allows opening files larger than 2 MB in the text editor.","compatiblePackages":[{"name":"pl.solidexplorer2","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Adds options to remove general ads.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Video ads","description":"Adds an option to remove ads in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Spoof device dimensions","description":"Adds an option to spoof the device dimensions which unlocks higher video qualities if they aren\u0027t available on the device.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable zoom haptics","description":"Adds an option to disable haptics when zooming.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass URL redirects","description":"Adds an option to bypass URL redirects and open the original URL directly.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Open links externally","description":"Adds an option to always open links in your browser instead of in the in-app-browser.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove tracking query parameter","description":"Adds an option to remove the tracking info from links you share.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Always repeat","description":"Adds an option to always repeat videos when they end.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Announcements","description":"Adds an option to show announcements from ReVanced on app startup.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Client spoof","description":"Adds options to spoof the client to allow video playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable debugging","description":"Adds options for debugging.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Unlocks options for picture-in-picture and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Seekbar tapping","description":"Adds an option to enable tap-to-seek on the seekbar of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable slide to seek","description":"Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable precise seeking gesture","description":"Adds an option to disable precise seeking when swiping up on the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Copy video URL","description":"Adds options to display buttons in the video player to copy video URLs.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"External downloads","description":"Adds support to download and save YouTube videos using an external downloader app.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove viewer discretion dialog","description":"Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds options to enable and configure volume and brightness swipe controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove player controls background","description":"Removes the dark background surrounding the video player controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Custom player overlay opacity","description":"Adds an option to change the opacity of the video player background when player controls are visible.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old seekbar thumbnails","description":"Adds an option to restore the old seekbar thumbnails that appear above the seekbar while seeking instead of fullscreen thumbnails.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof app version","description":"Adds an option to trick YouTube into thinking you are running an older version of the app. This can be used to restore old UI elements and features.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Return YouTube Dislike","description":"Adds an option to show the dislike count of videos using the Return YouTube Dislike API.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Adds options to hide menu items that appear when pressing the gear icon in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Adds an option to hide info cards that creators add in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Adds an option to hide the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Adds an option to hide suggested video cards at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Adds options to hide components related to comments.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable rolling number animations","description":"Adds an option to disable rolling number animations of video view count, user likes, and upload time.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable fullscreen ambient mode","description":"Adds an option to disable the ambient mode when in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide floating microphone button","description":"Adds an option to hide the floating microphone button when searching.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide layout components","description":"Adds options to hide general layout components.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Adds options to hide components related to YouTube Shorts.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide \u0027Load more\u0027 button","description":"Adds an option to hide the button under videos that loads similar videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide crowdfunding box","description":"Adds an option to hide the crowdfunding box between the player and video description.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Adds an option to hide the timestamp in the bottom left of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide breaking news shelf","description":"Adds an option to hide the breaking news shelf on the homepage tab.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable suggested video end screen","description":"Adds an option to disable the suggested video end screen at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide album cards","description":"Adds an option to hide album cards below artist descriptions.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide filter bar","description":"Adds options to hide the category bar at the top of video feeds.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom branding","description":"Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"appName","default":"YouTube ReVanced","values":{"YouTube ReVanced":"YouTube ReVanced","YT ReVanced":"YT ReVanced","YT":"YT","YouTube":"YouTube"},"title":"App name","description":"The name of the app.","required":false},{"key":"iconPath","default":"ReVanced*Logo","values":{"ReVanced Logo":"ReVanced*Logo"},"title":"App icon","description":"The path to a folder containing the following folders:\n\n- mipmap-xxxhdpi\n- mipmap-xxhdpi\n- mipmap-xhdpi\n- mipmap-hdpi\n- mipmap-mdpi\n\nEach of these folders has to have the following files:\n\n- adaptiveproduct_youtube_background_color_108.png\n- adaptiveproduct_youtube_foreground_color_108.png\n- ic_launcher.png\n- ic_launcher_round.png","required":false}]},{"name":"Change header","description":"Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"header","default":"ReVanced (borderless logo)","values":{"YouTube":"yt_wordmark_header","YouTube Premium":"yt_premium_wordmark_header","ReVanced":"ReVanced","ReVanced (borderless logo)":"ReVanced (borderless logo)"},"title":"Header","description":"Either a header name or a path to a custom header folder to use in the top bar.\nThe path to a folder must contain one or more of the following folders matching the DPI of your device:\n\n- drawable-xxxhdpi\n- drawable-xxhdpi\n- drawable-xhdpi\n- drawable-mdpi\n- drawable-hdpi\n\nThese folders must contain the following files:\n\n- yt_wordmark_header_light.png\n- yt_wordmark_header_dark.png","required":true}]},{"name":"Hide player buttons","description":"Adds an option to hide the previous and next buttons in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Navigation buttons","description":"Adds options to hide and change navigation buttons (such as the Shorts button).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide video action buttons","description":"Adds options to hide action buttons (such as the Download button) under videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide cast button","description":"Adds an option to hide the cast button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Adds an option to hide the captions button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide autoplay button","description":"Adds an option to hide the autoplay button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable tablet layout","description":"Adds an option to spoof the device form factor to a tablet which enables the tablet layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable resuming Shorts on startup","description":"Adds an option to disable the Shorts player from resuming on app startup when Shorts were last being watched.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change start page","description":"Adds an option to set which page the app opens in instead of the homepage.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Theme","description":"Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[{"key":"darkThemeBackgroundColor","default":"@android:color/black","values":{"Amoled black":"@android:color/black","Material You":"@android:color/system_neutral1_900","Classic (old YouTube)":"#FF212121","Catppuccin (Mocha)":"#FF181825","Dark pink":"#FF290025","Dark blue":"#FF001029","Dark green":"#FF002905","Dark yellow":"#FF282900","Dark orange":"#FF291800","Dark red":"#FF290000"},"title":"Dark theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false},{"key":"lightThemeBackgroundColor","default":"@android:color/white","values":{"White":"@android:color/white","Material You":"@android:color/system_neutral1_50","Catppuccin (Latte)":"#FFE6E9EF","Light pink":"#FFFCCFF3","Light blue":"#FFD1E0FF","Light green":"#FFCCFFCC","Light yellow":"#FFFDFFCC","Light orange":"#FFFFE6CC","Light red":"#FFFFD6D6"},"title":"Light theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false}]},{"name":"Disable auto captions","description":"Adds an option to disable captions from being automatically enabled.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Wide searchbar","description":"Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Adds an option to enable the tablet mini player layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Alternative thumbnails","description":"Adds options to replace video thumbnails using the DeArrow API or image captures from the video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable player popup panels","description":"Adds an option to disable panels (such as live chat) from opening automatically.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds an option to remember the last video quality selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"HDR auto brightness","description":"Adds an option to make the brightness of HDR videos follow the system default.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds options to customize available playback speeds and to remember the last playback speed selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old video quality menu","description":"Adds an option to restore the old video quality menu with specific video resolution options.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable Tumblr Live","description":"Disable the Tumblr Live tab button and dashboard carousel.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable gift message popup","description":"Disables the popup suggesting to buy TumblrMart items for other people.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable in-app update","description":"Disables the in-app update check and update prompt.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable blog notification reminder","description":"Disables the reminder to enable notifications for blogs you visit.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable dashboard ads","description":"Disables ads in the dashboard.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock plus","description":null,"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide update popup","description":"Prevents the update popup from showing up.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device ID","description":"Spoofs device ID to mitigate manual bans by developers.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Dynamic color","description":"Replaces the default X (Formerly Twitter) Blue with the user\u0027s Material You palette.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide recommended users","description":null,"compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides ads.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock downloads","description":"Unlocks the ability to download any video.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide view count","description":"Hides the view count of Posts.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Custom theme","description":"Applies a custom theme.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"backgroundColor","default":"@android:color/black","values":null,"title":"Primary background color","description":"The background color. Can be a hex color or a resource reference.","required":true},{"key":"backgroundColorSecondary","default":"#ff282828","values":null,"title":"Secondary background color","description":"The secondary background color. (e.g. search box, artist \u0026 podcast). Can be a hex color or a resource reference.","required":true},{"key":"accentColor","default":"#ff1ed760","values":null,"title":"Accent color","description":"The accent color (\u0027Spotify green\u0027 by default). Can be a hex color or a resource reference.","required":true},{"key":"accentColorPressed","default":"#ff169c46","values":null,"title":"Pressed dark theme accent color","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":true}]},{"name":"Enable on demand","description":"Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.","compatiblePackages":[{"name":"com.spotify.lite","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide premium navbar","description":"Removes the premium tab from the navbar.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Change package name","description":"Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"packageName","default":"Default","values":{"Default":"Default"},"title":"Package name","description":"The name of the package to rename the app to.","required":true}]},{"name":"Enable Android debugging","description":"Enables Android debugging capabilities. This can slow down the app.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Override certificate pinning","description":"Overrides certificate pinning, allowing to inspect traffic via a proxy.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Predictive back gesture","description":"Enables the predictive back gesture introduced on Android 13.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove screenshot restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Remove screen capture restriction","description":"Removes the restriction of capturing audio from apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Spoof SIM country","description":"Spoofs country information returned by the SIM card provider.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"networkCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Network ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false},{"key":"simCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Sim ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false}]},{"name":"Spoof Wi-Fi connection","description":"Spoofs an existing Wi-Fi connection.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Sanitize sharing links","description":"Removes (tracking) query parameters from the URLs when sharing links.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"free.reddit.news","versions":null},{"name":"reddit.news","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"dbrady://relay\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"infinity://localhost\".","required":true}]},{"name":"Unlock subscription","description":"Unlocks the subscription feature but requires a custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"o.o.joey","versions":null},{"name":"o.o.joey.pro","versions":null},{"name":"o.o.joey.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"https://127.0.0.1:65023/authorize_callback\".","required":true}]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"o.o.joey","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.rubenmayayo.reddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://rubenmayayo.com\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"me.ccrama.redditslide","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://www.ccrama.me\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.andrewshu.android.reddit","versions":null},{"name":"com.andrewshu.android.redditdonation","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"redditisfun://auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.onelouder.baconreader","versions":null},{"name":"com.onelouder.baconreader.premium","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://baconreader.com/auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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\".","required":true}]},{"name":"Fix /s/ links","description":"Fixes the issue where /s/ links do not work.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Disable Sync for Lemmy bottom sheet","description":"Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":["v23.06.30-13:39"]},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable screenshot popup","description":"Disables the popup that shows up when taking a screenshot.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium Reddit icons","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.awedea.nyx","versions":["2.2.7"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof signature","description":"Spoofs the signature of the app.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","compatiblePackages":[{"name":"com.ticktick.task","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Music video ads","description":"Removes ads in the music player.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Bypass certificate checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Permanent repeat","description":"Permanently remember your repeating preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Permanent shuffle","description":"Permanently remember your shuffle preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Codecs unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Exclusive audio playback","description":"Enables the option to play audio without video.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove upgrade button","description":"Removes the upgrade tab from the pivot bar.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Compact header","description":"Hides the music category bar at the top of the homepage.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Hide get premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback music","description":"Enables minimized playback on Kids music.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Background play","description":"Enables playing music in the background.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"jp.pxv.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show on lockscreen","description":"Shows student id and student ticket on lockscreen.","compatiblePackages":[{"name":"de.tudortmund.app","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Feed filter","description":"Removes ads, livestreams, stories, image videos and videos with a specific amount of views or likes from the feed.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SIM spoof","description":"Spoofs the information which is retrieved from the SIM card.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable login requirement","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Fix Google login","description":"Allows logging in with a Google account.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds ReVanced settings to TikTok.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show seekbar","description":"Shows progress bar for all video.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Downloads","description":"Removes download restrictions and changes the default path to download to.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Enables the playback speed option for all videos and retains the speed configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember clear display","description":"Remembers the clear display configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Promo code unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","compatiblePackages":[{"name":"de.dwd.warnapp","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable subscription suggestions","description":null,"compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock subscription features","description":"Unlocks \"Routes\", \"Matched Runs\" and \"Segment Efforts\".","compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Pro unlock","description":null,"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bka.serviceportal","versions":null}],"use":true,"requiresIntegrations":false,"options":[]}] \ No newline at end of file +[{"name":"Video ads","description":"Adds an option to remove ads in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Adds options to remove general ads.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device dimensions","description":"Adds an option to spoof the device dimensions which unlocks higher video qualities if they aren\u0027t available on the device.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Always repeat","description":"Adds an option to always repeat videos when they end.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Unlocks options for picture-in-picture and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove tracking query parameter","description":"Adds an option to remove the tracking info from links you share.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Announcements","description":"Adds an option to show announcements from ReVanced on app startup.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass URL redirects","description":"Adds an option to bypass URL redirects and open the original URL directly.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Open links externally","description":"Adds an option to always open links in your browser instead of in the in-app-browser.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Client spoof","description":"Adds options to spoof the client to allow video playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable zoom haptics","description":"Adds an option to disable haptics when zooming.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable debugging","description":"Adds options for debugging.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"HDR auto brightness","description":"Adds an option to make the brightness of HDR videos follow the system default.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old video quality menu","description":"Adds an option to restore the old video quality menu with specific video resolution options.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds options to customize available playback speeds and to remember the last playback speed selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds an option to remember the last video quality selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable slide to seek","description":"Adds an option to enable slide to seek instead of playing at 2x speed when pressing and holding in the video player. Including this patch may cause issues with tapping or double tapping the video player overlay.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable precise seeking gesture","description":"Adds an option to disable precise seeking when swiping up on the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Seekbar tapping","description":"Adds an option to enable tap-to-seek on the seekbar of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove viewer discretion dialog","description":"Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"External downloads","description":"Adds support to download and save YouTube videos using an external downloader app.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Copy video URL","description":"Adds options to display buttons in the video player to copy video URLs.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds options to enable and configure volume and brightness swipe controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old seekbar thumbnails","description":"Adds an option to restore the old seekbar thumbnails that appear above the seekbar while seeking instead of fullscreen thumbnails.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable player popup panels","description":"Adds an option to disable panels (such as live chat) from opening automatically.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change header","description":"Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"header","default":"revanced*borderless","values":{"YouTube":"header*","YouTube Premium":"premium*header","ReVanced":"revanced*","ReVanced (borderless logo)":"revanced*borderless"},"title":"Header","description":"The header to apply to the app.\n\nIf a path to a folder is provided, the folder must contain one or more of the following folders, depending on the DPI of the device:\n\n- drawable-xxxhdpi\n- drawable-xxhdpi\n- drawable-xhdpi\n- drawable-hdpi\n- drawable-mdpi\n\nEach of the folders must contain all of the following files:\n\n- yt_wordmark_header_light.png\n- yt_wordmark_header_dark.png\n\nThe image dimensions must be as follows:\n- drawable-xxxhdpi: 512px x 192px\n- drawable-xxhdpi: 387px x 144px\n- drawable-xhdpi: 258px x 96px\n- drawable-hdpi: 194px x 72px\n- drawable-mdpi: 129px x 48px","required":true}]},{"name":"Custom branding","description":"Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":false,"requiresIntegrations":false,"options":[{"key":"appName","default":"YouTube ReVanced","values":{"YouTube ReVanced":"YouTube ReVanced","YT ReVanced":"YT ReVanced","YT":"YT","YouTube":"YouTube"},"title":"App name","description":"The name of the app.","required":false},{"key":"iconPath","default":"ReVanced*Logo","values":{"ReVanced Logo":"ReVanced*Logo"},"title":"App icon","description":"The icon to apply to the app.\n\nIf a path to a folder is provided, the folder must contain the following folders:\n\n- mipmap-xxxhdpi\n- mipmap-xxhdpi\n- mipmap-xhdpi\n- mipmap-hdpi\n- mipmap-mdpi\n\nEach of these folders must contain the following files:\n\n- adaptiveproduct_youtube_background_color_108.png\n- adaptiveproduct_youtube_foreground_color_108.png\n- ic_launcher.png\n- ic_launcher_round.png","required":false}]},{"name":"Enable tablet layout","description":"Adds an option to spoof the device form factor to a tablet which enables the tablet layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Wide searchbar","description":"Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Adds an option to enable the tablet mini player layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Adds an option to hide the captions button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide autoplay button","description":"Adds an option to hide the autoplay button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide cast button","description":"Adds an option to hide the cast button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide player buttons","description":"Adds an option to hide the previous and next buttons in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Navigation buttons","description":"Adds options to hide and change navigation buttons (such as the Shorts button).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide video action buttons","description":"Adds options to hide action buttons (such as the Download button) under videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom player overlay opacity","description":"Adds an option to change the opacity of the video player background when player controls are visible.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove player controls background","description":"Removes the dark background surrounding the video player controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Alternative thumbnails","description":"Adds options to replace video thumbnails using the DeArrow API or image captures from the video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable resuming Shorts on startup","description":"Adds an option to disable the Shorts player from resuming on app startup when Shorts were last being watched.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Theme","description":"Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[{"key":"darkThemeBackgroundColor","default":"@android:color/black","values":{"Amoled black":"@android:color/black","Material You":"@android:color/system_neutral1_900","Classic (old YouTube)":"#FF212121","Catppuccin (Mocha)":"#FF181825","Dark pink":"#FF290025","Dark blue":"#FF001029","Dark green":"#FF002905","Dark yellow":"#FF282900","Dark orange":"#FF291800","Dark red":"#FF290000"},"title":"Dark theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false},{"key":"lightThemeBackgroundColor","default":"@android:color/white","values":{"White":"@android:color/white","Material You":"@android:color/system_neutral1_50","Catppuccin (Latte)":"#FFE6E9EF","Light pink":"#FFFCCFF3","Light blue":"#FFD1E0FF","Light green":"#FFCCFFCC","Light yellow":"#FFFDFFCC","Light orange":"#FFFFE6CC","Light red":"#FFFFD6D6"},"title":"Light theme background color","description":"Can be a hex color (#AARRGGBB) or a color resource reference.","required":false}]},{"name":"Spoof app version","description":"Adds an option to trick YouTube into thinking you are running an older version of the app. This can be used to restore old UI elements and features.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change start page","description":"Adds an option to set which page the app opens in instead of the homepage.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Adds an option to hide the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Adds options to hide components related to comments.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide breaking news shelf","description":"Adds an option to hide the breaking news shelf on the homepage tab.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Adds options to hide components related to YouTube Shorts.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable rolling number animations","description":"Adds an option to disable rolling number animations of video view count, user likes, and upload time.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide floating microphone button","description":"Adds an option to hide the floating microphone button when searching.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Adds an option to hide suggested video cards at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide crowdfunding box","description":"Adds an option to hide the crowdfunding box between the player and video description.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable suggested video end screen","description":"Adds an option to disable the suggested video end screen at the end of videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable fullscreen ambient mode","description":"Adds an option to disable the ambient mode when in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide \u0027Load more\u0027 button","description":"Adds an option to hide the button under videos that loads similar videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide album cards","description":"Adds an option to hide album cards below artist descriptions.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide filter bar","description":"Adds options to hide the category bar at the top of video feeds.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Adds options to hide menu items that appear when pressing the gear icon in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide layout components","description":"Adds options to hide general layout components.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Adds an option to hide the timestamp in the bottom left of the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Adds an option to hide info cards that creators add in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable auto captions","description":"Adds an option to disable captions from being automatically enabled.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.43","18.48.39","18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Return YouTube Dislike","description":"Adds an option to show the dislike count of videos using the Return YouTube Dislike API.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.49.37","19.01.34","19.02.39","19.03.35","19.03.36","19.04.37"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide story ads","description":"Hides the ads in the Facebook app stories.","compatiblePackages":[{"name":"com.facebook.katana","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable blog notification reminder","description":"Disables the reminder to enable notifications for blogs you visit.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable in-app update","description":"Disables the in-app update check and update prompt.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable gift message popup","description":"Disables the popup suggesting to buy TumblrMart items for other people.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable Tumblr Live","description":"Disable the Tumblr Live tab button and dashboard carousel.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable dashboard ads","description":"Disables ads in the dashboard.","compatiblePackages":[{"name":"com.tumblr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable typing indicator","description":"Disables the indicator while typing a message.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable switching emoji to sticker","description":"Disables switching from emoji to sticker search mode in message input field.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide inbox ads","description":"Hides ads in inbox.","compatiblePackages":[{"name":"com.facebook.orca","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.awedea.nyx","versions":["2.2.7"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable mandatory login","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock subscription features","description":"Unlocks \"Routes\", \"Matched Runs\" and \"Segment Efforts\".","compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable subscription suggestions","description":null,"compatiblePackages":[{"name":"com.strava","versions":["320.12"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove broadcasts restriction","description":"Enables starting/stopping NetGuard via broadcasts.","compatiblePackages":[{"name":"eu.faircode.netguard","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Spoof signature","description":"Spoofs the signature of the app.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.oe.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds ReVanced settings to TikTok.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable login requirement","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Fix Google login","description":"Allows logging in with a Google account.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SIM spoof","description":"Spoofs the information which is retrieved from the SIM card.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Show seekbar","description":"Shows progress bar for all video.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Enables the playback speed option for all videos and retains the speed configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember clear display","description":"Remembers the clear display configurations in between videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Downloads","description":"Removes download restrictions and changes the default path to download to.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Feed filter","description":"Removes ads, livestreams, stories, image videos and videos with a specific amount of views or likes from the feed.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["32.5.3"]},{"name":"com.zhiliaoapp.musically","versions":["32.5.3"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bka.serviceportal","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":["2.2 build 016"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block video ads","description":"Blocks video ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block embedded ads","description":"Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Block audio ads","description":"Blocks audio ads in streams and VODs.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Settings","description":"Adds settings menu to Twitch.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Debug mode","description":"Enables Twitch\u0027s internal debugging mode.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Show deleted messages","description":"Shows deleted chat messages behind a clickable spoiler.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Auto claim channel points","description":"Automatically claim Channel Points.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","16.9.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove bootloader detection","description":"Removes the check for an unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove root detection","description":"Removes the check for root permissions.","compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Music video ads","description":"Removes ads in the music player.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass certificate checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":true,"options":[{"key":"gmsCoreVendor","default":"com.mgoogle","values":{"Vanced":"com.mgoogle","ReVanced":"app.revanced"},"title":"GmsCore Vendor","description":"The group id of the GmsCore vendor.","required":true}]},{"name":"Permanent repeat","description":"Permanently remember your repeating preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Permanent shuffle","description":"Permanently remember your shuffle preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback music","description":"Enables minimized playback on Kids music.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove upgrade button","description":"Removes the upgrade tab from the pivot bar.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Compact header","description":"Hides the music category bar at the top of the homepage.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Hide get premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Background play","description":"Enables playing music in the background.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Exclusive audio playback","description":"Enables the option to play audio without video.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Codecs unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"jp.pxv.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show on lockscreen","description":"Shows student id and student ticket on lockscreen.","compatiblePackages":[{"name":"de.tudortmund.app","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":["4.29"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change package name","description":"Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"packageName","default":"Default","values":{"Default":"Default"},"title":"Package name","description":"The name of the package to rename the app to.","required":true}]},{"name":"Override certificate pinning","description":"Overrides certificate pinning, allowing to inspect traffic via a proxy.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Enable Android debugging","description":"Enables Android debugging capabilities. This can slow down the app.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove screen capture restriction","description":"Removes the restriction of capturing audio from apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Predictive back gesture","description":"Enables the predictive back gesture introduced on Android 13.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Spoof SIM country","description":"Spoofs country information returned by the SIM card provider.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"networkCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Network ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false},{"key":"simCountryIso","default":null,"values":{"Andorra":"AD","United Arab Emirates":"AE","Afghanistan":"AF","Antigua \u0026 Barbuda":"AG","Anguilla":"AI","Albania":"AL","Armenia":"AM","Angola":"AO","Antarctica":"AQ","Argentina":"AR","American Samoa":"AS","Austria":"AT","Australia":"AU","Aruba":"AW","Åland Islands":"AX","Azerbaijan":"AZ","Bosnia \u0026 Herzegovina":"BA","Barbados":"BB","Bangladesh":"BD","Belgium":"BE","Burkina Faso":"BF","Bulgaria":"BG","Bahrain":"BH","Burundi":"BI","Benin":"BJ","St. Barthélemy":"BL","Bermuda":"BM","Brunei":"BN","Bolivia":"BO","Caribbean Netherlands":"BQ","Brazil":"BR","Bahamas":"BS","Bhutan":"BT","Bouvet Island":"BV","Botswana":"BW","Belarus":"BY","Belize":"BZ","Canada":"CA","Cocos (Keeling) Islands":"CC","Congo - Kinshasa":"CD","Central African Republic":"CF","Congo - Brazzaville":"CG","Switzerland":"CH","Côte d’Ivoire":"CI","Cook Islands":"CK","Chile":"CL","Cameroon":"CM","China":"CN","Colombia":"CO","Costa Rica":"CR","Cuba":"CU","Cape Verde":"CV","Curaçao":"CW","Christmas Island":"CX","Cyprus":"CY","Czechia":"CZ","Germany":"DE","Djibouti":"DJ","Denmark":"DK","Dominica":"DM","Dominican Republic":"DO","Algeria":"DZ","Ecuador":"EC","Estonia":"EE","Egypt":"EG","Western Sahara":"EH","Eritrea":"ER","Spain":"ES","Ethiopia":"ET","Finland":"FI","Fiji":"FJ","Falkland Islands":"FK","Micronesia":"FM","Faroe Islands":"FO","France":"FR","Gabon":"GA","United Kingdom":"GB","Grenada":"GD","Georgia":"GE","French Guiana":"GF","Guernsey":"GG","Ghana":"GH","Gibraltar":"GI","Greenland":"GL","Gambia":"GM","Guinea":"GN","Guadeloupe":"GP","Equatorial Guinea":"GQ","Greece":"GR","South Georgia \u0026 South Sandwich Islands":"GS","Guatemala":"GT","Guam":"GU","Guinea-Bissau":"GW","Guyana":"GY","Hong Kong SAR China":"HK","Heard \u0026 McDonald Islands":"HM","Honduras":"HN","Croatia":"HR","Haiti":"HT","Hungary":"HU","Indonesia":"ID","Ireland":"IE","Israel":"IL","Isle of Man":"IM","India":"IN","British Indian Ocean Territory":"IO","Iraq":"IQ","Iran":"IR","Iceland":"IS","Italy":"IT","Jersey":"JE","Jamaica":"JM","Jordan":"JO","Japan":"JP","Kenya":"KE","Kyrgyzstan":"KG","Cambodia":"KH","Kiribati":"KI","Comoros":"KM","St. Kitts \u0026 Nevis":"KN","North Korea":"KP","South Korea":"KR","Kuwait":"KW","Cayman Islands":"KY","Kazakhstan":"KZ","Laos":"LA","Lebanon":"LB","St. Lucia":"LC","Liechtenstein":"LI","Sri Lanka":"LK","Liberia":"LR","Lesotho":"LS","Lithuania":"LT","Luxembourg":"LU","Latvia":"LV","Libya":"LY","Morocco":"MA","Monaco":"MC","Moldova":"MD","Montenegro":"ME","St. Martin":"MF","Madagascar":"MG","Marshall Islands":"MH","Macedonia":"MK","Mali":"ML","Myanmar (Burma)":"MM","Mongolia":"MN","Macau SAR China":"MO","Northern Mariana Islands":"MP","Martinique":"MQ","Mauritania":"MR","Montserrat":"MS","Malta":"MT","Mauritius":"MU","Maldives":"MV","Malawi":"MW","Mexico":"MX","Malaysia":"MY","Mozambique":"MZ","Namibia":"NA","New Caledonia":"NC","Niger":"NE","Norfolk Island":"NF","Nigeria":"NG","Nicaragua":"NI","Netherlands":"NL","Norway":"NO","Nepal":"NP","Nauru":"NR","Niue":"NU","New Zealand":"NZ","Oman":"OM","Panama":"PA","Peru":"PE","French Polynesia":"PF","Papua New Guinea":"PG","Philippines":"PH","Pakistan":"PK","Poland":"PL","St. Pierre \u0026 Miquelon":"PM","Pitcairn Islands":"PN","Puerto Rico":"PR","Palestinian Territories":"PS","Portugal":"PT","Palau":"PW","Paraguay":"PY","Qatar":"QA","Réunion":"RE","Romania":"RO","Serbia":"RS","Russia":"RU","Rwanda":"RW","Saudi Arabia":"SA","Solomon Islands":"SB","Seychelles":"SC","Sudan":"SD","Sweden":"SE","Singapore":"SG","St. Helena":"SH","Slovenia":"SI","Svalbard \u0026 Jan Mayen":"SJ","Slovakia":"SK","Sierra Leone":"SL","San Marino":"SM","Senegal":"SN","Somalia":"SO","Suriname":"SR","South Sudan":"SS","São Tomé \u0026 Príncipe":"ST","El Salvador":"SV","Sint Maarten":"SX","Syria":"SY","Swaziland":"SZ","Turks \u0026 Caicos Islands":"TC","Chad":"TD","French Southern Territories":"TF","Togo":"TG","Thailand":"TH","Tajikistan":"TJ","Tokelau":"TK","Timor-Leste":"TL","Turkmenistan":"TM","Tunisia":"TN","Tonga":"TO","Turkey":"TR","Trinidad \u0026 Tobago":"TT","Tuvalu":"TV","Taiwan":"TW","Tanzania":"TZ","Ukraine":"UA","Uganda":"UG","U.S. Outlying Islands":"UM","United States":"US","Uruguay":"UY","Uzbekistan":"UZ","Vatican City":"VA","St. Vincent \u0026 Grenadines":"VC","Venezuela":"VE","British Virgin Islands":"VG","U.S. Virgin Islands":"VI","Vietnam":"VN","Vanuatu":"VU","Wallis \u0026 Futuna":"WF","Samoa":"WS","Yemen":"YE","Mayotte":"YT","South Africa":"ZA","Zambia":"ZM","Zimbabwe":"ZW"},"title":"Sim ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false}]},{"name":"Remove screenshot restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Spoof Wi-Fi connection","description":"Spoofs an existing Wi-Fi connection.","compatiblePackages":null,"use":false,"requiresIntegrations":true,"options":[]},{"name":"Remove device restrictions","description":"Removes restrictions from using the app on any device. Requires mounting patched app over original.","compatiblePackages":[{"name":"com.google.android.apps.recorder","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device ID","description":"Spoofs device ID to mitigate manual bans by developers.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock plus","description":null,"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide update popup","description":"Prevents the update popup from showing up.","compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.32.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timeline ads","description":"Removes ads from the timeline.","compatiblePackages":[{"name":"com.instagram.android","versions":["275.0.0.27.98"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Sanitize sharing links","description":"Removes (tracking) query parameters from the URLs when sharing links.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"infinity://localhost\".","required":true}]},{"name":"Unlock subscription","description":"Unlocks the subscription feature but requires a custom client ID.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"free.reddit.news","versions":null},{"name":"reddit.news","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"dbrady://relay\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.andrewshu.android.reddit","versions":null},{"name":"com.andrewshu.android.redditdonation","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"redditisfun://auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"o.o.joey","versions":null},{"name":"o.o.joey.pro","versions":null},{"name":"o.o.joey.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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 \"https://127.0.0.1:65023/authorize_callback\".","required":true}]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"o.o.joey","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.onelouder.baconreader","versions":null},{"name":"com.onelouder.baconreader.premium","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://baconreader.com/auth\".","required":true}]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.rubenmayayo.reddit","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://rubenmayayo.com\".","required":true}]},{"name":"Disable Sync for Lemmy bottom sheet","description":"Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":["v23.06.30-13:39"]},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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\".","required":true}]},{"name":"Fix /s/ links","description":"Fixes the issue where /s/ links do not work.","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID.","compatiblePackages":[{"name":"me.ccrama.redditslide","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"client-id","default":null,"values":null,"title":"OAuth client ID","description":"The Reddit OAuth client ID. 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://www.ccrama.me\".","required":true}]},{"name":"Unlock premium Reddit icons","description":null,"compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable screenshot popup","description":"Disables the popup that shows up when taking a screenshot.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide recommended users","description":null,"compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides ads.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Dynamic color","description":"Replaces the default X (Formerly Twitter) Blue with the user\u0027s Material You palette.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock downloads","description":"Unlocks the ability to download any video.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide view count","description":"Hides the view count of Posts.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Pro unlock","description":null,"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable on demand","description":"Enables listening to songs on-demand, allowing to play any song from playlists, albums or artists without limitations. This does not remove ads.","compatiblePackages":[{"name":"com.spotify.lite","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide premium navbar","description":"Removes the premium tab from the navbar.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom theme","description":"Applies a custom theme.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"backgroundColor","default":"@android:color/black","values":null,"title":"Primary background color","description":"The background color. Can be a hex color or a resource reference.","required":true},{"key":"backgroundColorSecondary","default":"#ff282828","values":null,"title":"Secondary background color","description":"The secondary background color. (e.g. search box, artist \u0026 podcast). Can be a hex color or a resource reference.","required":true},{"key":"accentColor","default":"#ff1ed760","values":null,"title":"Accent color","description":"The accent color (\u0027Spotify green\u0027 by default). Can be a hex color or a resource reference.","required":true},{"key":"accentColorPressed","default":"#ff169c46","values":null,"title":"Pressed dark theme accent color","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":true}]},{"name":"Bypass root checks","description":"Removes the restriction to use the app with root permissions or on a custom ROM.","compatiblePackages":[{"name":"it.ipzs.cieid","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove file size limit","description":"Allows opening files larger than 2 MB in the text editor.","compatiblePackages":[{"name":"pl.solidexplorer2","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Promo code unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","compatiblePackages":[{"name":"de.dwd.warnapp","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove debugging detection","description":"Removes the USB and wireless debugging checks.","compatiblePackages":[{"name":"com.scb.phone","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Remove badge tab","description":"Removes the badge tab from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove notification badge","description":"Removes the red notification badge from the activity tab.","compatiblePackages":[{"name":"com.sony.songpal.mdr","versions":["10.1.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Hides most of the ads across the app.","compatiblePackages":[{"name":"com.myfitnesspal.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","compatiblePackages":[{"name":"com.ticktick.task","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]}] \ No newline at end of file From bdc54ef318e328be48f63f9443fe30df1a165712 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Tue, 13 Feb 2024 03:29:21 +0100 Subject: [PATCH 13/52] build: Bump dependencies This commit also migrates away from deprecated to new APIs --- api/revanced-patches.api | 1 + .../exportall/ExportAllActivitiesPatch.kt | 19 +- .../gestures/PredictiveBackGesturePatch.kt | 6 +- .../debugging/EnableAndroidDebuggingPatch.kt | 12 +- .../OverrideCertificatePinningPatch.kt | 14 +- .../packagename/ChangePackageNamePatch.kt | 50 +++--- .../all/misc/resources/AddResourcesPatch.kt | 165 +++++++++--------- .../BaseTransformInstructionsPatch.kt | 4 +- .../RemoveCaptureRestrictionResourcePatch.kt | 13 +- .../fingerprints/ExclusiveAudioFingerprint.kt | 51 ------ .../fingerprints/ServiceCheckFingerprint.kt | 4 +- .../misc/integrations/IntegrationsPatch.kt | 5 +- .../RemoveBroadcastsRestrictionPatch.kt | 15 +- .../reddit/ad/banner/HideBannerPatch.kt | 5 +- .../gms/BaseGmsCoreSupportResourcePatch.kt | 61 ++++--- .../misc/mapping/ResourceMappingPatch.kt | 9 +- .../settings/BaseSettingsResourcePatch.kt | 16 +- .../spotify/layout/theme/CustomThemePatch.kt | 39 +++-- .../tiktok/misc/spoof/sim/SpoofSimPatch.kt | 14 +- .../patches/tumblr/ads/DisableDashboardAds.kt | 10 +- .../inappupdate/DisableInAppUpdatePatch.kt | 6 +- .../tumblr/live/DisableTumblrLivePatch.kt | 6 +- .../misc/dynamiccolor/DynamicColorPatch.kt | 18 +- .../twitter/misc/hook/patch/BaseHookPatch.kt | 4 +- .../youtube/ad/general/HideAdsPatch.kt | 30 ++-- .../copyvideourl/CopyVideoUrlBytecodePatch.kt | 19 +- .../ExternalDownloadsBytecodePatch.kt | 21 ++- .../layout/branding/CustomBrandingPatch.kt | 4 +- .../branding/header/ChangeHeaderPatch.kt | 4 +- .../buttons/cast/HideCastButtonPatch.kt | 10 +- .../PlayerControlsBackgroundPatch.kt | 15 +- .../seekbar/SeekbarColorResourcePatch.kt | 14 +- .../sponsorblock/SponsorBlockResourcePatch.kt | 47 +++-- .../layout/theme/ThemeResourcePatch.kt | 56 +++--- .../BottomControlsResourcePatch.kt | 33 ++-- .../misc/settings/SettingsResourcePatch.kt | 34 ++-- .../youtube/video/speed/PlaybackSpeedPatch.kt | 13 +- .../kotlin/app/revanced/util/ResourceUtils.kt | 73 +++++--- 38 files changed, 464 insertions(+), 456 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 25de72ba..0cb9c02f 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1736,6 +1736,7 @@ public final class app/revanced/util/ResourceUtilsKt { public static final fun asSequence (Lorg/w3c/dom/NodeList;)Lkotlin/sequences/Sequence; public static final fun childElementsSequence (Lorg/w3c/dom/Node;)Lkotlin/sequences/Sequence; public static final fun copyResources (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;[Lapp/revanced/util/ResourceGroup;)V + public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/Document;Lapp/revanced/patcher/util/Document;)Ljava/lang/AutoCloseable; public static final fun copyXmlNode (Ljava/lang/String;Lapp/revanced/patcher/util/DomFileEditor;Lapp/revanced/patcher/util/DomFileEditor;)Ljava/lang/AutoCloseable; public static final fun doRecursively (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V public static final fun forEachChildElement (Lorg/w3c/dom/Node;Lkotlin/jvm/functions/Function1;)V diff --git a/src/main/kotlin/app/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch.kt b/src/main/kotlin/app/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch.kt index e9a38f53..88bcc6ec 100644 --- a/src/main/kotlin/app/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch.kt @@ -7,29 +7,32 @@ import app.revanced.patcher.patch.annotation.Patch @Patch( name = "Export all activities", description = "Makes all app activities exportable.", - use = false + use = false, ) @Suppress("unused") object ExportAllActivitiesPatch : ResourcePatch() { private const val EXPORTED_FLAG = "android:exported" + override fun execute(context: ResourceContext) { - context.xmlEditor["AndroidManifest.xml"].use { editor -> - val document = editor.file + context.document["AndroidManifest.xml"].use { document -> val activities = document.getElementsByTagName("activity") - for(i in 0..activities.length) { + for (i in 0..activities.length) { activities.item(i)?.apply { val exportedAttribute = attributes.getNamedItem(EXPORTED_FLAG) if (exportedAttribute != null) { - if (exportedAttribute.nodeValue != "true") + if (exportedAttribute.nodeValue != "true") { exportedAttribute.nodeValue = "true" + } } // Reason why the attribute is added in the case it does not exist: // https://github.com/revanced/revanced-patches/pull/1751/files#r1141481604 - else document.createAttribute(EXPORTED_FLAG) - .apply { value = "true" } - .let(attributes::setNamedItem) + else { + document.createAttribute(EXPORTED_FLAG) + .apply { value = "true" } + .let(attributes::setNamedItem) + } } } } diff --git a/src/main/kotlin/app/revanced/patches/all/interaction/gestures/PredictiveBackGesturePatch.kt b/src/main/kotlin/app/revanced/patches/all/interaction/gestures/PredictiveBackGesturePatch.kt index 3f3a0b9d..d0c08751 100644 --- a/src/main/kotlin/app/revanced/patches/all/interaction/gestures/PredictiveBackGesturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/interaction/gestures/PredictiveBackGesturePatch.kt @@ -7,16 +7,14 @@ import app.revanced.patcher.patch.annotation.Patch @Patch( name = "Predictive back gesture", description = "Enables the predictive back gesture introduced on Android 13.", - use = false + use = false, ) @Suppress("unused") object PredictiveBackGesturePatch : ResourcePatch() { private const val FLAG = "android:enableOnBackInvokedCallback" override fun execute(context: ResourceContext) { - context.xmlEditor["AndroidManifest.xml"].use { editor -> - val document = editor.file - + context.document["AndroidManifest.xml"].use { document -> with(document.getElementsByTagName("application").item(0)) { if (attributes.getNamedItem(FLAG) != null) return@with diff --git a/src/main/kotlin/app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch.kt index 902205e6..94605fb7 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/debugging/EnableAndroidDebuggingPatch.kt @@ -8,16 +8,16 @@ import org.w3c.dom.Element @Patch( name = "Enable Android debugging", description = "Enables Android debugging capabilities. This can slow down the app.", - use = false + use = false, ) @Suppress("unused") object EnableAndroidDebuggingPatch : ResourcePatch() { override fun execute(context: ResourceContext) { - context.xmlEditor["AndroidManifest.xml"].use { dom -> - val applicationNode = dom - .file - .getElementsByTagName("application") - .item(0) as Element + context.document["AndroidManifest.xml"].use { document -> + val applicationNode = + document + .getElementsByTagName("application") + .item(0) as Element // set application as debuggable applicationNode.setAttribute("android:debuggable", "true") diff --git a/src/main/kotlin/app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch.kt index d4403318..5bf14484 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/network/OverrideCertificatePinningPatch.kt @@ -11,16 +11,15 @@ import java.io.File name = "Override certificate pinning", description = "Overrides certificate pinning, allowing to inspect traffic via a proxy.", dependencies = [EnableAndroidDebuggingPatch::class], - use = false + use = false, ) @Suppress("unused") object OverrideCertificatePinningPatch : ResourcePatch() { override fun execute(context: ResourceContext) { - val resXmlDirectory = context["res/xml"] + val resXmlDirectory = context.get("res/xml", false) // Add android:networkSecurityConfig="@xml/network_security_config" and the "networkSecurityConfig" attribute if it does not exist. - context.xmlEditor["AndroidManifest.xml"].use { editor -> - val document = editor.file + context.document["AndroidManifest.xml"].use { document -> val applicationNode = document.getElementsByTagName("application").item(0) as Element if (!applicationNode.hasAttribute("networkSecurityConfig")) { @@ -54,7 +53,7 @@ object OverrideCertificatePinningPatch : ResourcePatch() { - """ + """, ) } else { // If the file already exists. @@ -63,12 +62,11 @@ object OverrideCertificatePinningPatch : ResourcePatch() { writeText( text.replace( "", - "\n\n" - ) + "\n\n", + ), ) } } - } } } diff --git a/src/main/kotlin/app/revanced/patches/all/misc/packagename/ChangePackageNamePatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/packagename/ChangePackageNamePatch.kt index ea847c4d..63d4bb2a 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/packagename/ChangePackageNamePatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/packagename/ChangePackageNamePatch.kt @@ -11,20 +11,21 @@ import java.io.Closeable @Patch( name = "Change package name", description = "Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.", - use = false + use = false, ) @Suppress("unused") object ChangePackageNamePatch : ResourcePatch(), Closeable { - private val packageNameOption = stringPatchOption( - key = "packageName", - default = "Default", - values = mapOf("Default" to "Default"), - title = "Package name", - description = "The name of the package to rename the app to.", - required = true - ) { - it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) - } + private val packageNameOption = + stringPatchOption( + key = "packageName", + default = "Default", + values = mapOf("Default" to "Default"), + title = "Package name", + description = "The name of the package to rename the app to.", + required = true, + ) { + it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) + } private lateinit var context: ResourceContext @@ -43,20 +44,25 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable { fun setOrGetFallbackPackageName(fallbackPackageName: String): String { val packageName = packageNameOption.value!! - return if (packageName == packageNameOption.default) + return if (packageName == packageNameOption.default) { fallbackPackageName.also { packageNameOption.value = it } - else + } else { packageName + } } - override fun close() = context.xmlEditor["AndroidManifest.xml"].use { editor -> - val replacementPackageName = packageNameOption.value + override fun close() = + context.document["AndroidManifest.xml"].use { document -> + val replacementPackageName = packageNameOption.value - val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element - manifest.setAttribute( - "package", - if (replacementPackageName != packageNameOption.default) replacementPackageName - else "${manifest.getAttribute("package")}.revanced" - ) - } + val manifest = document.getElementsByTagName("manifest").item(0) as Element + manifest.setAttribute( + "package", + if (replacementPackageName != packageNameOption.default) { + replacementPackageName + } else { + "${manifest.getAttribute("package")}.revanced" + }, + ) + } } diff --git a/src/main/kotlin/app/revanced/patches/all/misc/resources/AddResourcesPatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/resources/AddResourcesPatch.kt index bb72c077..0baf671f 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/resources/AddResourcesPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/resources/AddResourcesPatch.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.DomFileEditor +import app.revanced.patcher.util.Document import app.revanced.patches.all.misc.resources.AddResourcesPatch.resources import app.revanced.util.* import app.revanced.util.resource.ArrayResource @@ -19,6 +19,7 @@ import java.util.* * An identifier of an app. For example, `youtube`. */ private typealias AppId = String + /** * An identifier of a patch. For example, `ad.general.HideAdsPatch`. */ @@ -28,10 +29,12 @@ private typealias PatchId = String * A set of resources of a patch. */ private typealias PatchResources = MutableSet + /** * A map of resources belonging to a patch. */ private typealias AppResources = MutableMap + /** * A map of resources belonging to an app. */ @@ -67,40 +70,42 @@ object AddResourcesPatch : ResourcePatch(), MutableMap/.xml` into the map. - * - * @param value The value of the resource. For example, `values` or `values-de`. - * @param resourceKind The kind of the resource. For example, `strings` or `arrays`. - * @param transform A function that transforms the [Node]s from the XML files to a [BaseResource]. - */ - fun addResources( - value: Value, - resourceKind: String, - transform: (Node) -> BaseResource, - ) { - inputStreamFromBundledResource( - "addresources", - "$value/$resourceKind.xml" - )?.let { stream -> - // Add the resources associated with the given value to the map, - // instead of overwriting it. - // This covers the example case such as adding strings and arrays of the same value. - getOrPut(value, ::mutableMapOf).apply { - context.xmlEditor[stream].use { - it.file.getElementsByTagName("app").asSequence().forEach { app -> - val appId = app.attributes.getNamedItem("id").textContent + resources = + buildMap { + /** + * Puts resources under `/resources/addresources//.xml` into the map. + * + * @param value The value of the resource. For example, `values` or `values-de`. + * @param resourceKind The kind of the resource. For example, `strings` or `arrays`. + * @param transform A function that transforms the [Node]s from the XML files to a [BaseResource]. + */ + fun addResources( + value: Value, + resourceKind: String, + transform: (Node) -> BaseResource, + ) { + inputStreamFromBundledResource( + "addresources", + "$value/$resourceKind.xml", + )?.let { stream -> + // Add the resources associated with the given value to the map, + // instead of overwriting it. + // This covers the example case such as adding strings and arrays of the same value. + getOrPut(value, ::mutableMapOf).apply { + context.document[stream].use { + it.getElementsByTagName("app").asSequence().forEach { app -> + val appId = app.attributes.getNamedItem("id").textContent - getOrPut(appId, ::mutableMapOf).apply { - app.forEachChildElement { patch -> - val patchId = patch.attributes.getNamedItem("id").textContent + getOrPut(appId, ::mutableMapOf).apply { + app.forEachChildElement { patch -> + val patchId = patch.attributes.getNamedItem("id").textContent - getOrPut(patchId, ::mutableSetOf).apply { - patch.forEachChildElement { resourceNode -> - val resource = transform(resourceNode) + getOrPut(patchId, ::mutableSetOf).apply { + patch.forEachChildElement { resourceNode -> + val resource = transform(resourceNode) - add(resource) + add(resource) + } } } } @@ -109,23 +114,22 @@ object AddResourcesPatch : ResourcePatch(), MutableMap - addResources(value, "strings", StringResource::fromNode) + // Stage all resources to a temporary map. + // Staged resources consumed by AddResourcesPatch#invoke(PatchClass) + // are later used in AddResourcesPatch#close. + try { + val addStringResources = { value: Value -> + addResources(value, "strings", StringResource::fromNode) + } + Locale.getISOLanguages().asSequence().map { "values-$it" }.forEach { addStringResources(it) } + addStringResources("values") + + addResources("values", "arrays", ArrayResource::fromNode) + } catch (e: Exception) { + throw PatchException("Failed to read resources", e) } - Locale.getISOLanguages().asSequence().map { "values-$it" }.forEach { addStringResources(it) } - addStringResources("values") - - addResources("values", "arrays", ArrayResource::fromNode) - } catch (e: Exception) { - throw PatchException("Failed to read resources", e) } - } } /** @@ -136,8 +140,10 @@ object AddResourcesPatch : ResourcePatch(), MutableMap) = - getOrPut(value, ::mutableSetOf).addAll(resources) + operator fun invoke( + value: Value, + resources: Iterable, + ) = getOrPut(value, ::mutableSetOf).addAll(resources) /** * Adds a [StringResource]. @@ -177,10 +185,9 @@ object AddResourcesPatch : ResourcePatch(), MutableMap + items: List, ) = invoke("values", ArrayResource(name, items)) - /** * Puts all resources of any [Value] staged in [resources] for the given [PatchClass] to [AddResourcesPatch]. * @@ -209,7 +216,7 @@ object AddResourcesPatch : ResourcePatch(), MutableMap resources[appId]?.get(patchId)?.let { patchResources -> - if (invoke(value, patchResources)) result = true + if (invoke(value, patchResources)) result = true } } @@ -230,30 +237,32 @@ object AddResourcesPatch : ResourcePatch(), MutableMap>.invoke( + operator fun MutableMap>.invoke( value: Value, - resource: BaseResource + resource: BaseResource, ) { // TODO: Fix open-closed principle violation by modifying BaseResource#serialize so that it accepts - // a Value and the map of editors. It will then get or put the editor suitable for its resource type + // a Value and the map of documents. It will then get or put the document suitable for its resource type // to serialize itself to it. - val resourceFileName = when (resource) { - is StringResource -> "strings" - is ArrayResource -> "arrays" - else -> throw NotImplementedError("Unsupported resource type") - } - - getOrPut(resourceFileName) { - val targetFile = context["res/$value/$resourceFileName.xml"].also { - it.parentFile?.mkdirs() - it.createNewFile() + val resourceFileName = + when (resource) { + is StringResource -> "strings" + is ArrayResource -> "arrays" + else -> throw NotImplementedError("Unsupported resource type") } - context.xmlEditor[targetFile.path].let { editor -> + getOrPut(resourceFileName) { + val targetFile = + context.get("res/$value/$resourceFileName.xml", false).also { + it.parentFile?.mkdirs() + it.createNewFile() + } + + context.document[targetFile.path].let { document -> // Save the target node here as well - // in order to avoid having to call editor.getNode("resources") - // every time addUsingEditors is called but also save the editor so that it can be closed later. - editor to editor.getNode("resources") + // in order to avoid having to call document.getNode("resources") + // but also save the document so that it can be closed later. + document to document.getNode("resources") } }.let { (_, targetNode) -> targetNode.addResource(resource) { invoke(value, it) } @@ -261,17 +270,17 @@ object AddResourcesPatch : ResourcePatch(), MutableMap - // A map of editors associated by their kind (e.g. strings, arrays). - // Each editor is accompanied by the target node to which resources are added. - // A map is used because Map#getOrPut allows opening a new editor for the duration of a resource value. + // A map of document associated by their kind (e.g. strings, arrays). + // Each document is accompanied by the target node to which resources are added. + // A map is used because Map#getOrPut allows opening a new document for the duration of a resource value. // This is done to prevent having to open the files for every resource that is added. // Instead, it is cached once and reused for resources of the same value. - // This map is later accessed to close all editors for the current resource value. - val resourceFileEditors = mutableMapOf>() + // This map is later accessed to close all documents for the current resource value. + val documents = mutableMapOf>() - resources.forEach { resource -> resourceFileEditors(value, resource) } + resources.forEach { resource -> documents(value, resource) } - resourceFileEditors.values.forEach { (editor, _) -> editor.close() } + documents.values.forEach { (document, _) -> document.close() } } } } diff --git a/src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt index 68e8a68b..e651c4d6 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt @@ -9,12 +9,12 @@ import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @Suppress("MemberVisibilityCanBePrivate") -abstract class BaseTransformInstructionsPatch : BytecodePatch() { +abstract class BaseTransformInstructionsPatch : BytecodePatch(emptySet()) { abstract fun filterMap( classDef: ClassDef, method: Method, instruction: Instruction, - instructionIndex: Int + instructionIndex: Int, ): T? abstract fun transform(mutableMethod: MutableMethod, entry: T) diff --git a/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionResourcePatch.kt b/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionResourcePatch.kt index bd602f45..f38ce36f 100644 --- a/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionResourcePatch.kt @@ -8,16 +8,15 @@ import org.w3c.dom.Element @Patch(description = "Sets allowAudioPlaybackCapture in manifest to true.") internal object RemoveCaptureRestrictionResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { - // create an xml editor instance - context.xmlEditor["AndroidManifest.xml"].use { dom -> + context.document["AndroidManifest.xml"].use { document -> // get the application node - val applicationNode = dom - .file - .getElementsByTagName("application") - .item(0) as Element + val applicationNode = + document + .getElementsByTagName("application") + .item(0) as Element // set allowAudioPlaybackCapture attribute to true applicationNode.setAttribute("android:allowAudioPlaybackCapture", "true") } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt deleted file mode 100644 index db2e2f0e..00000000 --- a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt +++ /dev/null @@ -1,51 +0,0 @@ -package app.revanced.patches.music.audio.exclusiveaudio.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - - -@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. -internal object ExclusiveAudioFingerprint : MethodFingerprint( - "V", - AccessFlags.PUBLIC or AccessFlags.FINAL, - listOf("L", "Z"), - listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQ, - Opcode.CONST_4, - Opcode.GOTO, - Opcode.NOP, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.IF_EQZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.IF_EQZ, - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - Opcode.INVOKE_INTERFACE, - Opcode.GOTO, - Opcode.RETURN_VOID - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/ServiceCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/ServiceCheckFingerprint.kt index ca8db204..53604850 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/ServiceCheckFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/gms/fingerprints/ServiceCheckFingerprint.kt @@ -1,14 +1,12 @@ package app.revanced.patches.music.misc.gms.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags - internal object ServiceCheckFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "I"), - strings = listOf("Google Play Services not available") + strings = listOf("Google Play Services not available"), ) diff --git a/src/main/kotlin/app/revanced/patches/music/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/integrations/IntegrationsPatch.kt index 06f45d7e..ab061458 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/integrations/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/integrations/IntegrationsPatch.kt @@ -6,8 +6,5 @@ import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch @Patch(requiresIntegrations = true) object IntegrationsPatch : BaseIntegrationsPatch( - "Lapp/revanced/integrations/utils/ReVancedUtils;", - setOf( - ApplicationInitFingerprint, - ), + setOf(ApplicationInitFingerprint), ) diff --git a/src/main/kotlin/app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch.kt b/src/main/kotlin/app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch.kt index dc06778f..7afd5063 100644 --- a/src/main/kotlin/app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch.kt @@ -6,23 +6,22 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import org.w3c.dom.Element - @Patch( name = "Remove broadcasts restriction", description = "Enables starting/stopping NetGuard via broadcasts.", compatiblePackages = [CompatiblePackage("eu.faircode.netguard")], - use = false + use = false, ) @Suppress("unused") object RemoveBroadcastsRestrictionPatch : ResourcePatch() { override fun execute(context: ResourceContext) { - context.xmlEditor["AndroidManifest.xml"].use { dom -> - val applicationNode = dom - .file - .getElementsByTagName("application") - .item(0) as Element + context.document["AndroidManifest.xml"].use { document -> + val applicationNode = + document + .getElementsByTagName("application") + .item(0) as Element - applicationNode.getElementsByTagName("receiver").also { list -> + applicationNode.getElementsByTagName("receiver").also { list -> for (i in 0 until list.length) { val element = list.item(i) as? Element ?: continue if (element.getAttribute("android:name") == "eu.faircode.netguard.WidgetAdmin") { diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/banner/HideBannerPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/banner/HideBannerPatch.kt index 669d67b8..4e5a0090 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/banner/HideBannerPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/ad/banner/HideBannerPatch.kt @@ -9,8 +9,8 @@ object HideBannerPatch : ResourcePatch() { private const val RESOURCE_FILE_PATH = "res/layout/merge_listheader_link_detail.xml" override fun execute(context: ResourceContext) { - context.xmlEditor[RESOURCE_FILE_PATH].use { - it.file.getElementsByTagName("merge").item(0).childNodes.apply { + context.document[RESOURCE_FILE_PATH].use { + it.getElementsByTagName("merge").item(0).childNodes.apply { val attributes = arrayOf("height", "width") for (i in 1 until length) { @@ -30,4 +30,3 @@ object HideBannerPatch : ResourcePatch() { } } } - diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt index cfd80488..9e3d1a9a 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt @@ -22,19 +22,21 @@ abstract class BaseGmsCoreSupportResourcePatch( private val fromPackageName: String, private val toPackageName: String, private val spoofedPackageSignature: String, - dependencies: Set = setOf() + dependencies: Set = setOf(), ) : ResourcePatch(dependencies = setOf(ChangePackageNamePatch::class, AddResourcesPatch::class) + dependencies) { - internal val gmsCoreVendorOption = stringPatchOption( - key = "gmsCoreVendor", - default = "com.mgoogle", - values = mapOf( - "Vanced" to "com.mgoogle", - "ReVanced" to "app.revanced" - ), - title = "GmsCore Vendor", - description = "The group id of the GmsCore vendor.", - required = true - ) { it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) } + internal val gmsCoreVendorOption = + stringPatchOption( + key = "gmsCoreVendor", + default = "com.mgoogle", + values = + mapOf( + "Vanced" to "com.mgoogle", + "ReVanced" to "app.revanced", + ), + title = "GmsCore Vendor", + description = "The group id of the GmsCore vendor.", + required = true, + ) { it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) } protected val gmsCoreVendor by gmsCoreVendorOption @@ -49,17 +51,20 @@ abstract class BaseGmsCoreSupportResourcePatch( * Add metadata to manifest to support spoofing the package name and signature of GmsCore. */ private fun ResourceContext.addSpoofingMetadata() { - fun Node.adoptChild(tagName: String, block: Element.() -> Unit) { + fun Node.adoptChild( + tagName: String, + block: Element.() -> Unit, + ) { val child = ownerDocument.createElement(tagName) child.block() appendChild(child) } - xmlEditor["AndroidManifest.xml"].use { - val applicationNode = it - .file - .getElementsByTagName("application") - .item(0) + document["AndroidManifest.xml"].use { document -> + val applicationNode = + document + .getElementsByTagName("application") + .item(0) // Spoof package name and signature. applicationNode.adoptChild("meta-data") { @@ -87,27 +92,27 @@ abstract class BaseGmsCoreSupportResourcePatch( private fun ResourceContext.patchManifest() { val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(toPackageName) - val manifest = this["AndroidManifest.xml"].readText() - this["AndroidManifest.xml"].writeText( + val manifest = this.get("AndroidManifest.xml", false).readText() + this.get("AndroidManifest.xml", false).writeText( manifest.replace( "package=\"$fromPackageName", - "package=\"$packageName" + "package=\"$packageName", ).replace( "android:authorities=\"$fromPackageName", - "android:authorities=\"$packageName" + "android:authorities=\"$packageName", ).replace( "$fromPackageName.permission.C2D_MESSAGE", - "$packageName.permission.C2D_MESSAGE" + "$packageName.permission.C2D_MESSAGE", ).replace( "$fromPackageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION", - "$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION" + "$packageName.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION", ).replace( "com.google.android.c2dm", - "$gmsCoreVendor.android.c2dm" + "$gmsCoreVendor.android.c2dm", ).replace( "", - "" - ) + "", + ), ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt index c3b1ef20..9b27144d 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt @@ -7,7 +7,6 @@ import java.util.* import java.util.concurrent.Executors import java.util.concurrent.TimeUnit - object ResourceMappingPatch : ResourcePatch() { internal lateinit var resourceMappings: List private set @@ -17,15 +16,15 @@ object ResourceMappingPatch : ResourcePatch() { override fun execute(context: ResourceContext) { // save the file in memory to concurrently read from - val resourceXmlFile = context["res/values/public.xml"].readBytes() + val resourceXmlFile = context.get("res/values/public.xml", false).readBytes() // create a synchronized list to store the resource mappings val mappings = Collections.synchronizedList(mutableListOf()) for (threadIndex in 0 until THREAD_COUNT) { threadPoolExecutor.execute thread@{ - context.xmlEditor[resourceXmlFile.inputStream()].use { editor -> - val resources = editor.file.documentElement.childNodes + context.document[resourceXmlFile.inputStream()].use { document -> + val resources = document.documentElement.childNodes val resourcesLength = resources.length val jobSize = resourcesLength / THREAD_COUNT @@ -59,4 +58,4 @@ object ResourceMappingPatch : ResourcePatch() { } data class ResourceElement(val type: String, val name: String, val id: Long) -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt index d54601da..5ad4195c 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt @@ -21,16 +21,18 @@ import java.io.Closeable */ abstract class BaseSettingsResourcePatch( private val rootPreference: Pair? = null, - dependencies: Set = emptySet() + dependencies: Set = emptySet(), ) : ResourcePatch( - dependencies = setOf(AddResourcesPatch::class) + dependencies -), MutableSet by mutableSetOf(), Closeable { + dependencies = setOf(AddResourcesPatch::class) + dependencies, + ), + MutableSet by mutableSetOf(), + Closeable { private lateinit var context: ResourceContext override fun execute(context: ResourceContext) { context.copyResources( "settings", - ResourceGroup("xml", "revanced_prefs.xml") + ResourceGroup("xml", "revanced_prefs.xml"), ) this.context = context @@ -49,14 +51,14 @@ abstract class BaseSettingsResourcePatch( // Add the root preference to an existing fragment if needed. rootPreference?.let { (intentPreference, fragment) -> - context.xmlEditor["res/xml/$fragment.xml"].use { + context.document["res/xml/$fragment.xml"].use { it.getNode("PreferenceScreen").addPreference(intentPreference) } } // Add all preferences to the ReVanced fragment. - context.xmlEditor["res/xml/revanced_prefs.xml"].use { editor -> - val revancedPreferenceScreenNode = editor.getNode("PreferenceScreen") + context.document["res/xml/revanced_prefs.xml"].use { document -> + val revancedPreferenceScreenNode = document.getNode("PreferenceScreen") forEach { revancedPreferenceScreenNode.addPreference(it) } } } diff --git a/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt index 1faeae0a..2d839f16 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/layout/theme/CustomThemePatch.kt @@ -10,7 +10,7 @@ import org.w3c.dom.Element @Patch( name = "Custom theme", description = "Applies a custom theme.", - compatiblePackages = [CompatiblePackage("com.spotify.music")] + compatiblePackages = [CompatiblePackage("com.spotify.music")], ) @Suppress("unused") object CustomThemePatch : ResourcePatch() { @@ -19,7 +19,7 @@ object CustomThemePatch : ResourcePatch() { default = "@android:color/black", title = "Primary background color", description = "The background color. Can be a hex color or a resource reference.", - required = true + required = true, ) private var backgroundColorSecondary by stringPatchOption( @@ -27,7 +27,7 @@ object CustomThemePatch : ResourcePatch() { default = "#ff282828", title = "Secondary background color", description = "The secondary background color. (e.g. search box, artist & podcast). Can be a hex color or a resource reference.", - required = true + required = true, ) private var accentColor by stringPatchOption( @@ -35,16 +35,17 @@ object CustomThemePatch : ResourcePatch() { default = "#ff1ed760", title = "Accent color", description = "The accent color ('Spotify green' by default). Can be a hex color or a resource reference.", - required = true + required = true, ) private var accentColorPressed by stringPatchOption( key = "accentColorPressed", default = "#ff169c46", title = "Pressed dark theme accent color", - description = "The color when accented buttons are pressed, by default slightly darker than accent. " - + "Can be a hex color or a resource reference.", - required = true + description = + "The color when accented buttons are pressed, by default slightly darker than accent. " + + "Can be a hex color or a resource reference.", + required = true, ) override fun execute(context: ResourceContext) { @@ -53,24 +54,26 @@ object CustomThemePatch : ResourcePatch() { val accentColor = accentColor!! val accentColorPressed = accentColorPressed!! - context.xmlEditor["res/values/colors.xml"].use { editor -> - val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element + context.document["res/values/colors.xml"].use { document -> + val resourcesNode = document.getElementsByTagName("resources").item(0) as Element for (i in 0 until resourcesNode.childNodes.length) { val node = resourcesNode.childNodes.item(i) as? Element ?: continue - node.textContent = when (node.getAttribute("name")) { - "dark_base_background_elevated_base", "design_dark_default_color_background", - "design_dark_default_color_surface", "gray_7", "gray_background", "gray_layer", - "sthlm_blk" -> backgroundColor + node.textContent = + when (node.getAttribute("name")) { + "dark_base_background_elevated_base", "design_dark_default_color_background", + "design_dark_default_color_surface", "gray_7", "gray_background", "gray_layer", + "sthlm_blk", + -> backgroundColor - "gray_15" -> backgroundColorSecondary + "gray_15" -> backgroundColorSecondary - "dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor + "dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor - "dark_brightaccent_background_press" -> accentColorPressed - else -> continue - } + "dark_brightaccent_background_press" -> accentColorPressed + else -> continue + } } } } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt index 39d412d2..1c40b5d9 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/SpoofSimPatch.kt @@ -23,19 +23,19 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference dependencies = [IntegrationsPatch::class, SettingsPatch::class], compatiblePackages = [ CompatiblePackage("com.ss.android.ugc.trill"), - CompatiblePackage("com.zhiliaoapp.musically") + CompatiblePackage("com.zhiliaoapp.musically"), ], - use = false + use = false, ) @Suppress("unused") -object SpoofSimPatch : BytecodePatch() { +object SpoofSimPatch : BytecodePatch(emptySet()) { private val replacements = hashMapOf( "getSimCountryIso" to "getCountryIso", "getNetworkCountryIso" to "getCountryIso", "getSimOperator" to "getOperator", "getNetworkOperator" to "getOperator", "getSimOperatorName" to "getOperatorName", - "getNetworkOperatorName" to "getOperatorName" + "getNetworkOperatorName" to "getOperatorName", ) override fun execute(context: BytecodeContext) { @@ -85,7 +85,7 @@ object SpoofSimPatch : BytecodePatch() { with(SettingsStatusLoadFingerprint.result!!.mutableMethod) { addInstruction( 0, - "invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableSimSpoof()V" + "invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableSimSpoof()V", ) } } @@ -99,7 +99,7 @@ object SpoofSimPatch : BytecodePatch() { """ invoke-static {v$resultReg}, Lapp/revanced/integrations/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String; move-result-object v$resultReg - """ + """, ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/tumblr/ads/DisableDashboardAds.kt b/src/main/kotlin/app/revanced/patches/tumblr/ads/DisableDashboardAds.kt index 09972604..77d31b9f 100644 --- a/src/main/kotlin/app/revanced/patches/tumblr/ads/DisableDashboardAds.kt +++ b/src/main/kotlin/app/revanced/patches/tumblr/ads/DisableDashboardAds.kt @@ -10,11 +10,11 @@ import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch name = "Disable dashboard ads", description = "Disables ads in the dashboard.", compatiblePackages = [CompatiblePackage("com.tumblr")], - dependencies = [TimelineFilterPatch::class] + dependencies = [TimelineFilterPatch::class], ) @Suppress("unused") -object DisableDashboardAds : BytecodePatch() { - override fun execute(context: BytecodeContext) { +object DisableDashboardAds : BytecodePatch(emptySet()) { + override fun execute(context: BytecodeContext) { // The timeline object types are filtered by their name in the TimelineObjectType enum. // This is often different from the "object_type" returned in the api (noted in comments here) arrayOf( @@ -29,9 +29,9 @@ object DisableDashboardAds : BytecodePatch() { "DISPLAY_IO_INTERSCROLLER_AD", // "display_io_interscroller" "DISPLAY_IO_HEADLINE_VIDEO_AD", // "display_io_headline_video" "FACEBOOK_BIDDAABLE", // "facebook_biddable_sdk_ad" - "GOOGLE_NATIVE" // "google_native_ad" + "GOOGLE_NATIVE", // "google_native_ad" ).forEach { TimelineFilterPatch.addObjectTypeFilter(it) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch.kt b/src/main/kotlin/app/revanced/patches/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch.kt index 574f5c38..c9664d54 100644 --- a/src/main/kotlin/app/revanced/patches/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch.kt +++ b/src/main/kotlin/app/revanced/patches/tumblr/annoyances/inappupdate/DisableInAppUpdatePatch.kt @@ -10,13 +10,13 @@ import app.revanced.patches.tumblr.featureflags.OverrideFeatureFlagsPatch name = "Disable in-app update", description = "Disables the in-app update check and update prompt.", dependencies = [OverrideFeatureFlagsPatch::class], - compatiblePackages = [CompatiblePackage("com.tumblr")] + compatiblePackages = [CompatiblePackage("com.tumblr")], ) @Suppress("unused") -object DisableInAppUpdatePatch : BytecodePatch() { +object DisableInAppUpdatePatch : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) { // Before checking for updates using Google Play core AppUpdateManager, the value of this feature flag is checked. // If this flag is false or the last update check was today and no update check is performed. OverrideFeatureFlagsPatch.addOverride("inAppUpdate", "false") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/tumblr/live/DisableTumblrLivePatch.kt b/src/main/kotlin/app/revanced/patches/tumblr/live/DisableTumblrLivePatch.kt index 1c9ec2a8..8cbdaca6 100644 --- a/src/main/kotlin/app/revanced/patches/tumblr/live/DisableTumblrLivePatch.kt +++ b/src/main/kotlin/app/revanced/patches/tumblr/live/DisableTumblrLivePatch.kt @@ -11,10 +11,10 @@ import app.revanced.patches.tumblr.timelinefilter.TimelineFilterPatch name = "Disable Tumblr Live", description = "Disable the Tumblr Live tab button and dashboard carousel.", dependencies = [OverrideFeatureFlagsPatch::class, TimelineFilterPatch::class], - compatiblePackages = [CompatiblePackage("com.tumblr")] + compatiblePackages = [CompatiblePackage("com.tumblr")], ) @Suppress("unused") -object DisableTumblrLivePatch : BytecodePatch() { +object DisableTumblrLivePatch : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) { // Hide the LIVE_MARQUEE timeline element that appears in the feed // Called "live_marquee" in api response @@ -23,4 +23,4 @@ object DisableTumblrLivePatch : BytecodePatch() { // Hide the Tab button for Tumblr Live by forcing the feature flag to false OverrideFeatureFlagsPatch.addOverride("liveStreaming", "false") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt index 1d0a3326..0b33fdc3 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch.kt @@ -11,12 +11,12 @@ import java.nio.file.Files @Patch( name = "Dynamic color", description = "Replaces the default X (Formerly Twitter) Blue with the user's Material You palette.", - compatiblePackages = [CompatiblePackage("com.twitter.android")] + compatiblePackages = [CompatiblePackage("com.twitter.android")], ) @Suppress("unused") object DynamicColorPatch : ResourcePatch() { override fun execute(context: ResourceContext) { - val resDirectory = context["res"] + val resDirectory = context.get("res", false) if (!resDirectory.isDirectory) throw PatchException("The res folder can not be found.") val valuesV31Directory = resDirectory.resolve("values-v31") @@ -28,16 +28,14 @@ object DynamicColorPatch : ResourcePatch() { listOf(valuesV31Directory, valuesNightV31Directory).forEach { it -> val colorsXml = it.resolve("colors.xml") - if(!colorsXml.exists()) { + if (!colorsXml.exists()) { FileWriter(colorsXml).use { it.write("") } } } - context.xmlEditor["res/values-v31/colors.xml"].use { editor -> - val document = editor.file - + context.document["res/values-v31/colors.xml"].use { document -> mapOf( "ps__twitter_blue" to "@color/twitter_blue", "ps__twitter_blue_pressed" to "@color/twitter_blue_fill_pressed", @@ -46,7 +44,7 @@ object DynamicColorPatch : ResourcePatch() { "twitter_blue_opacity_30" to "@android:color/system_accent1_100", "twitter_blue_opacity_50" to "@android:color/system_accent1_200", "twitter_blue_opacity_58" to "@android:color/system_accent1_300", - "deep_transparent_twitter_blue" to "@android:color/system_accent1_200" + "deep_transparent_twitter_blue" to "@android:color/system_accent1_200", ).forEach { (k, v) -> val colorElement = document.createElement("color") @@ -57,16 +55,14 @@ object DynamicColorPatch : ResourcePatch() { } } - context.xmlEditor["res/values-night-v31/colors.xml"].use { editor -> - val document = editor.file - + context.document["res/values-night-v31/colors.xml"].use { document -> mapOf( "twitter_blue" to "@android:color/system_accent1_200", "twitter_blue_fill_pressed" to "@android:color/system_accent1_300", "twitter_blue_opacity_30" to "@android:color/system_accent1_50", "twitter_blue_opacity_50" to "@android:color/system_accent1_100", "twitter_blue_opacity_58" to "@android:color/system_accent1_200", - "deep_transparent_twitter_blue" to "@android:color/system_accent1_200" + "deep_transparent_twitter_blue" to "@android:color/system_accent1_200", ).forEach { (k, v) -> val colorElement = document.createElement("color") diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch.kt index 74c83fb1..dace2301 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patches.twitter.misc.hook.json.JsonHookPatch -abstract class BaseHookPatch(private val hookClassDescriptor: String) : BytecodePatch() { +abstract class BaseHookPatch(private val hookClassDescriptor: String) : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) = JsonHookPatch.hooks.addHook(JsonHookPatch.Hook(context, hookClassDescriptor)) -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt index d487bfea..b73927b6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt @@ -1,7 +1,5 @@ package app.revanced.patches.youtube.ad.general -import app.revanced.util.findMutableMethodOf -import app.revanced.util.injectHideViewCall import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage @@ -9,6 +7,8 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.shared.misc.fix.verticalscroll.VerticalScrollPatch import app.revanced.patches.youtube.ad.getpremium.HideGetPremiumPatch import app.revanced.patches.youtube.misc.fix.backtoexitgesture.FixBackToExitGesturePatch +import app.revanced.util.findMutableMethodOf +import app.revanced.util.injectHideViewCall import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c @@ -20,11 +20,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c HideGetPremiumPatch::class, HideAdsResourcePatch::class, VerticalScrollPatch::class, - FixBackToExitGesturePatch::class + FixBackToExitGesturePatch::class, ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", [ + "com.google.android.youtube", + [ "18.32.39", "18.37.36", "18.38.44", @@ -37,30 +38,33 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) - ] + "19.04.37", + ], + ), + ], ) @Suppress("unused") -object HideAdsPatch : BytecodePatch() { +object HideAdsPatch : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) { context.classes.forEach { classDef -> classDef.methods.forEach { method -> with(method.implementation) { this?.instructions?.forEachIndexed { index, instruction -> - if (instruction.opcode != Opcode.CONST) + if (instruction.opcode != Opcode.CONST) { return@forEachIndexed + } // Instruction to store the id adAttribution into a register - if ((instruction as Instruction31i).wideLiteral != HideAdsResourcePatch.adAttributionId) + if ((instruction as Instruction31i).wideLiteral != HideAdsResourcePatch.adAttributionId) { return@forEachIndexed + } val insertIndex = index + 1 // Call to get the view with the id adAttribution with(instructions.elementAt(insertIndex)) { - if (opcode != Opcode.INVOKE_VIRTUAL) + if (opcode != Opcode.INVOKE_VIRTUAL) { return@forEachIndexed + } // Hide the view val viewRegister = (this as Instruction35c).registerC @@ -71,7 +75,7 @@ object HideAdsPatch : BytecodePatch() { insertIndex, viewRegister, "Lapp/revanced/integrations/youtube/patches/components/AdsFilter;", - "hideAdAttributionView" + "hideAdAttributionView", ) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt index 9d23802f..894d3085 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt @@ -13,28 +13,29 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch dependencies = [ CopyVideoUrlResourcePatch::class, PlayerControlsBytecodePatch::class, - VideoInformationPatch::class + VideoInformationPatch::class, ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", [ + "com.google.android.youtube", + [ "18.48.39", "18.49.37", "19.01.34", "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) - ] + "19.04.37", + ], + ), + ], ) @Suppress("unused") -object CopyVideoUrlBytecodePatch : BytecodePatch() { +object CopyVideoUrlBytecodePatch : BytecodePatch(emptySet()) { private const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/youtube/videoplayer" private val BUTTONS_DESCRIPTORS = listOf( "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlButton;", - "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;" + "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;", ) override fun execute(context: BytecodeContext) { @@ -44,4 +45,4 @@ object CopyVideoUrlBytecodePatch : BytecodePatch() { PlayerControlsBytecodePatch.injectVisibilityCheckCall("$descriptor->changeVisibility(Z)V") } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt index 9a2bd645..fdda9fdb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt @@ -13,24 +13,25 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch dependencies = [ ExternalDownloadsResourcePatch::class, PlayerControlsBytecodePatch::class, - VideoInformationPatch::class + VideoInformationPatch::class, ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", [ + "com.google.android.youtube", + [ "18.48.39", "18.49.37", "19.01.34", "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] + "19.04.37", + ], ), - ] + ], ) @Suppress("unused") -object ExternalDownloadsBytecodePatch : BytecodePatch() { +object ExternalDownloadsBytecodePatch : BytecodePatch(emptySet()) { private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;" override fun execute(context: BytecodeContext) { @@ -39,13 +40,15 @@ object ExternalDownloadsBytecodePatch : BytecodePatch() { */ PlayerControlsBytecodePatch.initializeControl( - "$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V") + "$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V", + ) /* add code to change the visibility of the control */ PlayerControlsBytecodePatch.injectVisibilityCheckCall( - "$BUTTON_DESCRIPTOR->changeVisibility(Z)V") + "$BUTTON_DESCRIPTOR->changeVisibility(Z)V", + ) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt index 19aa116b..d0fc001e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/CustomBrandingPatch.kt @@ -81,7 +81,7 @@ object CustomBrandingPatch : ResourcePatch() { }.let { resourceGroups -> if (icon != REVANCED_ICON) { val path = File(icon) - val resourceDirectory = context["res"] + val resourceDirectory = context.get("res", false) resourceGroups.forEach { group -> val fromDirectory = path.resolve(group.resourceDirectoryName) @@ -102,7 +102,7 @@ object CustomBrandingPatch : ResourcePatch() { appName?.let { name -> // Change the app name. - val manifest = context["AndroidManifest.xml"] + val manifest = context.get("AndroidManifest.xml", false) manifest.writeText( manifest.readText() .replace( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt index f02b982d..61fe82a1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -71,7 +71,7 @@ object ChangeHeaderPatch : ResourcePatch() { override fun execute(context: ResourceContext) { // The directories to copy the header to. val targetResourceDirectories = targetResourceDirectoryNames.keys.mapNotNull { - context["res"].resolve(it).takeIf(File::exists) + context.get("res", false).resolve(it).takeIf(File::exists) } // The files to replace in the target directories. val targetResourceFiles = targetResourceDirectoryNames.keys.map { directoryName -> @@ -120,7 +120,7 @@ object ChangeHeaderPatch : ResourcePatch() { // For each source folder, copy the files to the target resource directories. sourceFolders.forEach { dpiSourceFolder -> - val targetDpiFolder = context["res"].resolve(dpiSourceFolder.name) + val targetDpiFolder = context.get("res", false).resolve(dpiSourceFolder.name) if (!targetDpiFolder.exists()) return@forEach val imgSourceFiles = dpiSourceFolder.listFiles { file -> file.isFile }!! diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt index ee1f6943..24dda9fd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt @@ -17,13 +17,13 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch dependencies = [ IntegrationsPatch::class, SettingsPatch::class, - AddResourcesPatch::class + AddResourcesPatch::class, ], compatiblePackages = [ - CompatiblePackage("com.google.android.youtube") - ] + CompatiblePackage("com.google.android.youtube"), + ], ) -object HideCastButtonPatch : BytecodePatch() { +object HideCastButtonPatch : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) @@ -38,7 +38,7 @@ object HideCastButtonPatch : BytecodePatch() { """ invoke-static {p1}, Lapp/revanced/integrations/youtube/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I move-result p1 - """ + """, ) } ?: throw PatchException("setVisibility method not found.") } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt index 66638a2b..8c3d5a7b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/background/PlayerControlsBackgroundPatch.kt @@ -12,7 +12,8 @@ import org.w3c.dom.Element description = "Removes the dark background surrounding the video player controls.", compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", [ + "com.google.android.youtube", + [ "18.32.39", "18.37.36", "18.38.44", @@ -25,19 +26,19 @@ import org.w3c.dom.Element "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) + "19.04.37", + ], + ), ], - use = false + use = false, ) @Suppress("unused") object PlayerControlsBackgroundPatch : ResourcePatch() { private const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml" override fun execute(context: ResourceContext) { - context.xmlEditor[RESOURCE_FILE_PATH].use { editor -> - editor.file.doRecursively node@{ node -> + context.document[RESOURCE_FILE_PATH].use { document -> + document.doRecursively node@{ node -> if (node !is Element) return@node node.getAttributeNode("android:color")?.let { attribute -> diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorResourcePatch.kt index 5c7d6272..cb70ee44 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorResourcePatch.kt @@ -9,7 +9,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch import org.w3c.dom.Element @Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) -internal object SeekbarColorResourcePatch : ResourcePatch(){ +internal object SeekbarColorResourcePatch : ResourcePatch() { internal var reelTimeBarPlayedColorId = -1L internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L internal var inlineTimeBarPlayedNotHighlightedColorId = -1L @@ -18,7 +18,7 @@ internal object SeekbarColorResourcePatch : ResourcePatch(){ fun findColorResource(resourceName: String): Long { return ResourceMappingPatch.resourceMappings .find { it.type == "color" && it.name == resourceName }?.id - ?: throw PatchException("Could not find color resource: $resourceName") + ?: throw PatchException("Could not find color resource: $resourceName") } reelTimeBarPlayedColorId = @@ -29,16 +29,18 @@ internal object SeekbarColorResourcePatch : ResourcePatch(){ findColorResource("inline_time_bar_played_not_highlighted_color") // Edit the resume playback drawable and replace the progress bar with a custom drawable - context.xmlEditor["res/drawable/resume_playback_progressbar_drawable.xml"].use { editor -> - val layerList = editor.file.getElementsByTagName("layer-list").item(0) as Element + context.document["res/drawable/resume_playback_progressbar_drawable.xml"].use { document -> + val layerList = document.getElementsByTagName("layer-list").item(0) as Element val progressNode = layerList.getElementsByTagName("item").item(1) as Element if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) { throw PatchException("Could not find progress bar") } val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element - val replacementNode = editor.file.createElement( - "app.revanced.integrations.youtube.patches.theme.ProgressBarDrawable") + val replacementNode = + document.createElement( + "app.revanced.integrations.youtube.patches.theme.ProgressBarDrawable", + ) scaleNode.replaceChild(replacementNode, shapeNode) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt index a8c347b2..272ce36e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt @@ -17,26 +17,25 @@ import app.revanced.util.inputStreamFromBundledResource dependencies = [ SettingsPatch::class, ResourceMappingPatch::class, - AddResourcesPatch::class - ] + AddResourcesPatch::class, + ], ) internal object SponsorBlockResourcePatch : ResourcePatch() { - override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( IntentPreference( "revanced_sb_settings", - intent = SettingsPatch.newIntent("revanced_sb_settings_intent") - ) + intent = SettingsPatch.newIntent("revanced_sb_settings_intent"), + ), ) arrayOf( ResourceGroup( "layout", "revanced_sb_inline_sponsor_overlay.xml", "revanced_sb_new_segment.xml", - "revanced_sb_skip_sponsor_button.xml" + "revanced_sb_skip_sponsor_button.xml", ), ResourceGroup( // required resource for back button, because when the base APK is used, this resource will not exist @@ -46,37 +45,47 @@ internal object SponsorBlockResourcePatch : ResourcePatch() { "revanced_sb_edit.xml", "revanced_sb_logo.xml", "revanced_sb_publish.xml", - "revanced_sb_voting.xml" + "revanced_sb_voting.xml", ), ResourceGroup( // required resource for back button, because when the base APK is used, this resource will not exist - "drawable-xxxhdpi", "quantum_ic_skip_next_white_24.png" - ) + "drawable-xxxhdpi", + "quantum_ic_skip_next_white_24.png", + ), ).forEach { resourceGroup -> context.copyResources("sponsorblock", resourceGroup) } // copy nodes from host resources to their real xml files - val hostingResourceStream = inputStreamFromBundledResource( - "sponsorblock", - "host/layout/youtube_controls_layout.xml" - )!! + val hostingResourceStream = + inputStreamFromBundledResource( + "sponsorblock", + "host/layout/youtube_controls_layout.xml", + )!! var modifiedControlsLayout = false - val targetXmlEditor = context.xmlEditor["res/layout/youtube_controls_layout.xml"] + val targetDocument = context.document["res/layout/youtube_controls_layout.xml"] "RelativeLayout".copyXmlNode( - context.xmlEditor[hostingResourceStream], - targetXmlEditor + context.document[hostingResourceStream], + targetDocument, ).also { - val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes + val children = targetDocument.getElementsByTagName("RelativeLayout").item(0).childNodes // Replace the startOf with the voting button view so that the button does not overlap for (i in 1 until children.length) { val view = children.item(i) // Replace the attribute for a specific node only - if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button"))) continue + if (!( + view.hasAttributes() && + view.attributes.getNamedItem( + "android:id", + ).nodeValue.endsWith("live_chat_overlay_button") + ) + ) { + continue + } // voting button id from the voting button view from the youtube_controls_layout.xml host file val votingButtonId = "@+id/revanced_sb_voting_button" @@ -90,4 +99,4 @@ internal object SponsorBlockResourcePatch : ResourcePatch() { if (!modifiedControlsLayout) throw PatchException("Could not modify controls layout") } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt index d379514e..cf5e351c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt @@ -20,8 +20,8 @@ import org.w3c.dom.Element SettingsPatch::class, ResourceMappingPatch::class, SeekbarPreferencesPatch::class, - AddResourcesPatch::class - ] + AddResourcesPatch::class, + ], ) internal object ThemeResourcePatch : ResourcePatch() { private const val SPLASH_BACKGROUND_COLOR = "revanced_splash_background_color" @@ -31,28 +31,29 @@ internal object ThemeResourcePatch : ResourcePatch() { SeekbarPreferencesPatch.addPreferences( SwitchPreference("revanced_seekbar_custom_color"), - TextPreference("revanced_seekbar_custom_color_value", inputType = InputType.TEXT_CAP_CHARACTERS) + TextPreference("revanced_seekbar_custom_color_value", inputType = InputType.TEXT_CAP_CHARACTERS), ) // Edit theme colors via resources. - context.xmlEditor["res/values/colors.xml"].use { editor -> - val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element + context.document["res/values/colors.xml"].use { document -> + val resourcesNode = document.getElementsByTagName("resources").item(0) as Element val children = resourcesNode.childNodes for (i in 0 until children.length) { val node = children.item(i) as? Element ?: continue - node.textContent = when (node.getAttribute("name")) { - "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3", - "yt_black4", "yt_status_bar_background_dark", "material_grey_850" - -> darkThemeBackgroundColor ?: continue + node.textContent = + when (node.getAttribute("name")) { + "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3", + "yt_black4", "yt_status_bar_background_dark", "material_grey_850", + -> darkThemeBackgroundColor ?: continue - "yt_white1", "yt_white1_opacity95", "yt_white1_opacity98", - "yt_white2", "yt_white3", "yt_white4", - -> lightThemeBackgroundColor ?: continue + "yt_white1", "yt_white1_opacity95", "yt_white1_opacity98", + "yt_white2", "yt_white3", "yt_white4", + -> lightThemeBackgroundColor ?: continue - else -> continue - } + else -> continue + } } } @@ -68,14 +69,15 @@ internal object ThemeResourcePatch : ResourcePatch() { // Edit splash screen files and change the background color, // if the background colors are set. if (darkThemeBackgroundColor != null && lightThemeBackgroundColor != null) { - val splashScreenResourceFiles = listOf( - "res/drawable/quantum_launchscreen_youtube.xml", - "res/drawable-sw600dp/quantum_launchscreen_youtube.xml" - ) + val splashScreenResourceFiles = + listOf( + "res/drawable/quantum_launchscreen_youtube.xml", + "res/drawable-sw600dp/quantum_launchscreen_youtube.xml", + ) splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile -> - context.xmlEditor[resourceFile].use { - val layerList = it.file.getElementsByTagName("layer-list").item(0) as Element + context.document[resourceFile].use { + val layerList = it.getElementsByTagName("layer-list").item(0) as Element val childNodes = layerList.childNodes for (i in 0 until childNodes.length) { @@ -89,24 +91,24 @@ internal object ThemeResourcePatch : ResourcePatch() { } } } - } private fun addColorResource( context: ResourceContext, resourceFile: String, colorName: String, - colorValue: String + colorValue: String, ) { - context.xmlEditor[resourceFile].use { - val resourcesNode = it.file.getElementsByTagName("resources").item(0) as Element + context.document[resourceFile].use { + val resourcesNode = it.getElementsByTagName("resources").item(0) as Element resourcesNode.appendChild( - it.file.createElement("color").apply { + it.createElement("color").apply { setAttribute("name", colorName) setAttribute("category", "color") textContent = colorValue - }) + }, + ) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch.kt index 6dcc92c7..4cd94140 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/BottomControlsResourcePatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.playercontrols import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.DomFileEditor +import app.revanced.patcher.util.Document import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import java.io.Closeable @@ -18,14 +18,15 @@ object BottomControlsResourcePatch : ResourcePatch(), Closeable { private var lastLeftOf = "fullscreen_button" private lateinit var resourceContext: ResourceContext - private lateinit var targetXmlEditor: DomFileEditor + private lateinit var targetDocument: Document override fun execute(context: ResourceContext) { resourceContext = context - targetXmlEditor = context.xmlEditor[TARGET_RESOURCE] + targetDocument = context.document[TARGET_RESOURCE] - bottomUiContainerResourceId = ResourceMappingPatch.resourceMappings - .single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id + bottomUiContainerResourceId = + ResourceMappingPatch.resourceMappings + .single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id } /** @@ -34,18 +35,18 @@ object BottomControlsResourcePatch : ResourcePatch(), Closeable { * @param resourceDirectoryName The name of the directory containing the hosting resource. */ fun addControls(resourceDirectoryName: String) { - val sourceXmlEditor = resourceContext.xmlEditor[ - this::class.java.classLoader.getResourceAsStream( - "$resourceDirectoryName/host/layout/$TARGET_RESOURCE_NAME" - )!! - ] + val sourceDocument = + resourceContext.document[ + this::class.java.classLoader.getResourceAsStream( + "$resourceDirectoryName/host/layout/$TARGET_RESOURCE_NAME", + )!!, + ] val targetElement = "android.support.constraint.ConstraintLayout" - val hostElements = sourceXmlEditor.file.getElementsByTagName(targetElement).item(0).childNodes + val hostElements = sourceDocument.getElementsByTagName(targetElement).item(0).childNodes - val destinationResourceFile = targetXmlEditor.file - val destinationElement = destinationResourceFile.getElementsByTagName(targetElement).item(0) + val destinationElement = targetDocument.getElementsByTagName(targetElement).item(0) for (index in 1 until hostElements.length) { val element = hostElements.item(index).cloneNode(true) @@ -63,11 +64,11 @@ object BottomControlsResourcePatch : ResourcePatch(), Closeable { lastLeftOf = element.attributes.getNamedItem("android:id").nodeValue.substring(nameSpaceLength) // Add the element. - destinationResourceFile.adoptNode(element) + targetDocument.adoptNode(element) destinationElement.appendChild(element) } - sourceXmlEditor.close() + sourceDocument.close() } - override fun close() = targetXmlEditor.close() + override fun close() = targetDocument.close() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt index b4b50461..5083cecf 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt @@ -12,12 +12,13 @@ import org.w3c.dom.Element object SettingsResourcePatch : BaseSettingsResourcePatch( IntentPreference( "revanced_settings", - intent = SettingsPatch.newIntent("revanced_settings_intent") + intent = SettingsPatch.newIntent("revanced_settings_intent"), ) to "settings_fragment", - dependencies = setOf( - ResourceMappingPatch::class, - AddResourcesPatch::class, - ) + dependencies = + setOf( + ResourceMappingPatch::class, + AddResourcesPatch::class, + ), ) { // Used for a fingerprint from SettingsPatch. internal var appearanceStringId = -1L @@ -28,12 +29,13 @@ object SettingsResourcePatch : BaseSettingsResourcePatch( AddResourcesPatch(this::class) // Used for a fingerprint from SettingsPatch. - appearanceStringId = ResourceMappingPatch.resourceMappings.find { - it.type == "string" && it.name == "app_theme_appearance_dark" - }!!.id + appearanceStringId = + ResourceMappingPatch.resourceMappings.find { + it.type == "string" && it.name == "app_theme_appearance_dark" + }!!.id arrayOf( - ResourceGroup("layout", "revanced_settings_with_toolbar.xml") + ResourceGroup("layout", "revanced_settings_with_toolbar.xml"), ).forEach { resourceGroup -> context.copyResources("settings", resourceGroup) } @@ -41,20 +43,20 @@ object SettingsResourcePatch : BaseSettingsResourcePatch( // Modify the manifest and add a data intent filter to the LicenseActivity. // Some devices freak out if undeclared data is passed to an intent, // and this change appears to fix the issue. - context.xmlEditor["AndroidManifest.xml"].use { editor -> + context.document["AndroidManifest.xml"].use { document -> // A xml regular-expression would probably work better than this manual searching. - val manifestNodes = editor.file.getElementsByTagName("manifest").item(0).childNodes + val manifestNodes = document.getElementsByTagName("manifest").item(0).childNodes for (i in 0..manifestNodes.length) { val node = manifestNodes.item(i) if (node != null && node.nodeName == "application") { val applicationNodes = node.childNodes for (j in 0..applicationNodes.length) { val applicationChild = applicationNodes.item(j) - if (applicationChild is Element && applicationChild.nodeName == "activity" - && applicationChild.getAttribute("android:name") == "com.google.android.libraries.social.licenses.LicenseActivity" + if (applicationChild is Element && applicationChild.nodeName == "activity" && + applicationChild.getAttribute("android:name") == "com.google.android.libraries.social.licenses.LicenseActivity" ) { - val intentFilter = editor.file.createElement("intent-filter") - val mimeType = editor.file.createElement("data") + val intentFilter = document.createElement("intent-filter") + val mimeType = document.createElement("data") mimeType.setAttribute("android:mimeType", "text/plain") intentFilter.appendChild(mimeType) applicationChild.appendChild(intentFilter) @@ -65,4 +67,4 @@ object SettingsResourcePatch : BaseSettingsResourcePatch( } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt index 07be6f2e..bbaf5371 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/PlaybackSpeedPatch.kt @@ -13,20 +13,21 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa dependencies = [CustomPlaybackSpeedPatch::class, RememberPlaybackSpeedPatch::class], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", [ + "com.google.android.youtube", + [ "18.48.39", "18.49.37", "19.01.34", "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) - ] + "19.04.37", + ], + ), + ], ) @Suppress("unused") -object PlaybackSpeedPatch : BytecodePatch() { +object PlaybackSpeedPatch : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) { // All patches this patch depends on succeed. } diff --git a/src/main/kotlin/app/revanced/util/ResourceUtils.kt b/src/main/kotlin/app/revanced/util/ResourceUtils.kt index c5b502cb..3189f663 100644 --- a/src/main/kotlin/app/revanced/util/ResourceUtils.kt +++ b/src/main/kotlin/app/revanced/util/ResourceUtils.kt @@ -1,8 +1,8 @@ package app.revanced.util import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.util.Document import app.revanced.patcher.util.DomFileEditor -import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.util.resource.BaseResource import org.w3c.dom.Node import org.w3c.dom.NodeList @@ -25,9 +25,10 @@ fun Node.childElementsSequence() = this.childNodes.asSequence().filter { it.node /** * Performs the given [action] on each child element. */ -fun Node.forEachChildElement(action: (Node) -> Unit) = childElementsSequence().forEach { - action(it) -} +fun Node.forEachChildElement(action: (Node) -> Unit) = + childElementsSequence().forEach { + action(it) + } /** * Recursively traverse the DOM tree starting from the given root node. @@ -45,15 +46,19 @@ fun Node.doRecursively(action: (Node) -> Unit) { * @param sourceResourceDirectory The source resource directory name. * @param resources The resources to copy. */ -fun ResourceContext.copyResources(sourceResourceDirectory: String, vararg resources: ResourceGroup) { - val targetResourceDirectory = this["res"] +fun ResourceContext.copyResources( + sourceResourceDirectory: String, + vararg resources: ResourceGroup, +) { + val targetResourceDirectory = this.get("res", false) for (resourceGroup in resources) { resourceGroup.resources.forEach { resource -> val resourceFile = "${resourceGroup.resourceDirectoryName}/$resource" Files.copy( inputStreamFromBundledResource(sourceResourceDirectory, resourceFile)!!, - targetResourceDirectory.resolve(resourceFile).toPath(), StandardCopyOption.REPLACE_EXISTING + targetResourceDirectory.resolve(resourceFile).toPath(), + StandardCopyOption.REPLACE_EXISTING, ) } } @@ -61,7 +66,7 @@ fun ResourceContext.copyResources(sourceResourceDirectory: String, vararg resour internal fun inputStreamFromBundledResource( sourceResourceDirectory: String, - resourceFile: String + resourceFile: String, ): InputStream? = classLoader.getResourceAsStream("$sourceResourceDirectory/$resourceFile") /** @@ -80,29 +85,29 @@ class ResourceGroup(val resourceDirectoryName: String, vararg val resources: Str fun ResourceContext.iterateXmlNodeChildren( resource: String, targetTag: String, - callback: (node: Node) -> Unit -) = - xmlEditor[classLoader.getResourceAsStream(resource)!!].use { - val stringsNode = it.file.getElementsByTagName(targetTag).item(0).childNodes - for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i)) - } - + callback: (node: Node) -> Unit, +) = document[classLoader.getResourceAsStream(resource)!!].use { + val stringsNode = it.getElementsByTagName(targetTag).item(0).childNodes + for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i)) +} /** - * Copies the specified node of the source [DomFileEditor] to the target [DomFileEditor]. - * @param source the source [DomFileEditor]. - * @param target the target [DomFileEditor]- - * @return AutoCloseable that closes the target [DomFileEditor]s. + * Copies the specified node of the source [Document] to the target [Document]. + * @param source the source [Document]. + * @param target the target [Document]- + * @return AutoCloseable that closes the [Document]s. */ -fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable { - val hostNodes = source.file.getElementsByTagName(this).item(0).childNodes +fun String.copyXmlNode( + source: Document, + target: Document, +): AutoCloseable { + val hostNodes = source.getElementsByTagName(this).item(0).childNodes - val destinationResourceFile = target.file - val destinationNode = destinationResourceFile.getElementsByTagName(this).item(0) + val destinationNode = target.getElementsByTagName(this).item(0) for (index in 0 until hostNodes.length) { val node = hostNodes.item(index).cloneNode(true) - destinationResourceFile.adoptNode(node) + target.adoptNode(node) destinationNode.appendChild(node) } @@ -112,14 +117,30 @@ fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoClosea } } +@Deprecated( + "Use copyXmlNode(Document, Document) instead.", + ReplaceWith( + "this.copyXmlNode(source.file as Document, target.file as Document)", + "app.revanced.patcher.util.Document", + "app.revanced.patcher.util.Document", + ), +) +fun String.copyXmlNode( + source: DomFileEditor, + target: DomFileEditor, +) = this.copyXmlNode(source.file as Document, target.file as Document) + /** * Add a resource node child. * * @param resource The resource to add. * @param resourceCallback Called when a resource has been processed. */ -internal fun Node.addResource(resource: BaseResource, resourceCallback: (BaseResource) -> Unit = { }) { +internal fun Node.addResource( + resource: BaseResource, + resourceCallback: (BaseResource) -> Unit = { }, +) { appendChild(resource.serialize(ownerDocument, resourceCallback)) } -internal fun DomFileEditor?.getNode(tagName: String) = this!!.file.getElementsByTagName(tagName).item(0) \ No newline at end of file +internal fun Document?.getNode(tagName: String) = this!!.getElementsByTagName(tagName).item(0) From d789fd6b5af70862c91a3f57aed15ce042fc33ce Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 15 Feb 2024 04:38:06 +0100 Subject: [PATCH 14/52] build: Sign release artifacts --- .github/workflows/release.yml | 7 ++ .releaserc | 2 +- api/revanced-patches.api | 4 + build.gradle.kts | 75 +++++++++++-------- gradle/libs.versions.toml | 4 +- .../JsonPatchesFileGenerator.kt | 12 +-- .../kotlin/app/revanced/generator/Main.kt | 12 +++ .../generator/PatchesFileGenerator.kt | 7 ++ .../revanced/meta/IPatchesFileGenerator.kt | 20 ----- 9 files changed, 85 insertions(+), 58 deletions(-) rename src/main/kotlin/app/revanced/{meta => generator}/JsonPatchesFileGenerator.kt (87%) create mode 100644 src/main/kotlin/app/revanced/generator/Main.kt create mode 100644 src/main/kotlin/app/revanced/generator/PatchesFileGenerator.kt delete mode 100644 src/main/kotlin/app/revanced/meta/IPatchesFileGenerator.kt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4c4e7962..fb968d13 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -41,6 +41,13 @@ jobs: - name: Install dependencies run: npm install + - name: Import GPG key + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + fingerprint: ${{ env.GPG_FINGERPRINT }} + - name: Release env: GITHUB_TOKEN: ${{ secrets.REPOSITORY_PUSH_ACCESS }} diff --git a/.releaserc b/.releaserc index 0e4fa8b8..6193511b 100644 --- a/.releaserc +++ b/.releaserc @@ -33,7 +33,7 @@ { "assets": [ { - "path": "build/libs/*.jar" + "path": "build/libs/revanced-patches*" }, { "path": "patches.json" diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 0cb9c02f..50a135fb 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1,3 +1,7 @@ +public final class app/revanced/generator/MainKt { + public static synthetic fun main ([Ljava/lang/String;)V +} + public final class app/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch : app/revanced/patcher/patch/ResourcePatch { public static final field INSTANCE Lapp/revanced/patches/all/activity/exportall/ExportAllActivitiesPatch; public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V diff --git a/build.gradle.kts b/build.gradle.kts index 5e9743b5..b1486a4b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,9 +1,10 @@ import org.gradle.kotlin.dsl.support.listFilesOrdered plugins { - kotlin("jvm") version "1.9.22" + alias(libs.plugins.kotlin) alias(libs.plugins.binary.compatibility.validator) `maven-publish` + signing } group = "app.revanced" @@ -12,7 +13,14 @@ repositories { mavenCentral() mavenLocal() google() - maven { url = uri("https://jitpack.io") } + maven { + // A repository must be speficied for some reason. "registry" is a dummy. + url = uri("https://maven.pkg.github.com/revanced/registry") + credentials { + username = project.findProperty("gpr.user") as String? ?: System.getenv("GITHUB_ACTOR") + password = project.findProperty("gpr.key") as String? ?: System.getenv("GITHUB_TOKEN") + } + } } dependencies { @@ -28,25 +36,26 @@ kotlin { jvmToolchain(11) } -tasks.withType(Jar::class) { - exclude("app/revanced/meta") - - manifest { - attributes["Name"] = "ReVanced Patches" - attributes["Description"] = "Patches for ReVanced." - attributes["Version"] = version - attributes["Timestamp"] = System.currentTimeMillis().toString() - attributes["Source"] = "git@github.com:revanced/revanced-patches.git" - attributes["Author"] = "ReVanced" - attributes["Contact"] = "contact@revanced.app" - attributes["Origin"] = "https://revanced.app" - attributes["License"] = "GNU General Public License v3.0" - } -} - tasks { - register("generateBundle") { - description = "Generate DEX files and add them in the JAR file" + withType(Jar::class) { + exclude("app/revanced/meta") + + manifest { + attributes["Name"] = "ReVanced Patches" + attributes["Description"] = "Patches for ReVanced." + attributes["Version"] = version + attributes["Timestamp"] = System.currentTimeMillis().toString() + attributes["Source"] = "git@github.com:revanced/revanced-patches.git" + attributes["Author"] = "ReVanced" + attributes["Contact"] = "contact@revanced.app" + attributes["Origin"] = "https://revanced.app" + attributes["License"] = "GNU General Public License v3.0" + } + } + + register("buildDexJar") { + description = "Build and add a DEX to the JAR file" + group = "build" dependsOn(build) @@ -54,35 +63,35 @@ tasks { val d8 = File(System.getenv("ANDROID_HOME")).resolve("build-tools") .listFilesOrdered().last().resolve("d8").absolutePath - val artifacts = configurations.archives.get().allArtifacts.files.files.first().absolutePath + val patchesJar = configurations.archives.get().allArtifacts.files.files.first().absolutePath val workingDirectory = layout.buildDirectory.dir("libs").get().asFile exec { workingDir = workingDirectory - commandLine = listOf(d8, artifacts) + commandLine = listOf(d8, patchesJar) } exec { workingDir = workingDirectory - commandLine = listOf("zip", "-u", artifacts, "classes.dex") + commandLine = listOf("zip", "-u", patchesJar, "classes.dex") } } } - register("generateMeta") { - description = "Generate metadata for this bundle" + register("generatePatchesFiles") { + description = "Generate patches files" dependsOn(build) classpath = sourceSets["main"].runtimeClasspath - mainClass.set("app.revanced.meta.IPatchesFileGenerator") + mainClass.set("app.revanced.generator.MainKt") } - // Required to run tasks because Gradle semantic-release plugin runs the publish task. + // Needed by gradle-semantic-release-plugin. // Tracking: https://github.com/KengoTODA/gradle-semantic-release-plugin/issues/435 - named("publish") { - dependsOn("generateBundle") - dependsOn("generateMeta") + publish { + dependsOn("buildDexJar") + dependsOn("generatePatchesFiles") } } @@ -118,3 +127,9 @@ publishing { } } } + +signing { + useGpgCmd() + + sign(publishing.publications["revanced-patches-publication"]) +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 2b26096f..7596f26a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,9 +1,10 @@ [versions] -revanced-patcher = "19.2.0" +revanced-patcher = "19.3.1" smali = "3.0.4" guava = "33.0.0-jre" gson = "2.10.1" binary-compatibility-validator = "0.14.0" +kotlin = "1.9.22" [libraries] revanced-patcher = { module = "app.revanced:revanced-patcher", version.ref = "revanced-patcher" } @@ -13,3 +14,4 @@ gson = { module = "com.google.code.gson:gson", version.ref = "gson" } [plugins] binary-compatibility-validator = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "binary-compatibility-validator" } +kotlin = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } diff --git a/src/main/kotlin/app/revanced/meta/JsonPatchesFileGenerator.kt b/src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt similarity index 87% rename from src/main/kotlin/app/revanced/meta/JsonPatchesFileGenerator.kt rename to src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt index 6755706c..28871d6d 100644 --- a/src/main/kotlin/app/revanced/meta/JsonPatchesFileGenerator.kt +++ b/src/main/kotlin/app/revanced/generator/JsonPatchesFileGenerator.kt @@ -1,11 +1,11 @@ -package app.revanced.meta +package app.revanced.generator import app.revanced.patcher.PatchSet import app.revanced.patcher.patch.Patch import com.google.gson.GsonBuilder import java.io.File -internal class JsonPatchesFileGenerator : IPatchesFileGenerator { +internal class JsonPatchesFileGenerator : PatchesFileGenerator { override fun generate(patches: PatchSet) = patches.map { JsonPatch( it.name!!, @@ -20,9 +20,9 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator { option.values, option.title, option.description, - option.required + option.required, ) - } + }, ) }.let { File("patches.json").writeText(GsonBuilder().serializeNulls().create().toJson(it)) @@ -35,7 +35,7 @@ internal class JsonPatchesFileGenerator : IPatchesFileGenerator { val compatiblePackages: Set? = null, val use: Boolean = true, val requiresIntegrations: Boolean = false, - val options: List - """, - ) - } else { - // If the file already exists. - readText().let { text -> - if (!text.contains("")) { - writeText( - text.replace( - "", - "\n\n", - ), - ) - } - } - } + """.trimIndentMultiline(), + ) } } } From a22ed46ae0aa56086008d272b73ab0a80cddd50d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Wed, 28 Feb 2024 22:04:01 +0000 Subject: [PATCH 40/52] chore(release): 4.3.0-dev.9 [skip ci] # [4.3.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.8...v4.3.0-dev.9) (2024-02-28) ### Bug Fixes * **Override certificate pinning:** Always overwrite with a generic network security configuration ([2a842a1](https://github.com/ReVanced/revanced-patches/commit/2a842a1e14e1993eb028ae0bd1a93e227bb929a6)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b8250bc..c71e3521 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.8...v4.3.0-dev.9) (2024-02-28) + + +### Bug Fixes + +* **Override certificate pinning:** Always overwrite with a generic network security configuration ([2a842a1](https://github.com/ReVanced/revanced-patches/commit/2a842a1e14e1993eb028ae0bd1a93e227bb929a6)) + # [4.3.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.7...v4.3.0-dev.8) (2024-02-28) diff --git a/gradle.properties b/gradle.properties index 5eccbcd6..c090138a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.8 +version = 4.3.0-dev.9 From 9466d973c6d7a2891e3fa9f283107b64399152ea Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Thu, 29 Feb 2024 01:16:06 +0100 Subject: [PATCH 41/52] fix(YouTube - Spoof app version): Remove broken versions (#2776) --- src/main/resources/addresources/values/arrays.xml | 6 ------ src/main/resources/addresources/values/strings.xml | 3 --- 2 files changed, 9 deletions(-) diff --git a/src/main/resources/addresources/values/arrays.xml b/src/main/resources/addresources/values/arrays.xml index 5ea6b7c2..908b80ee 100644 --- a/src/main/resources/addresources/values/arrays.xml +++ b/src/main/resources/addresources/values/arrays.xml @@ -5,17 +5,11 @@ @string/revanced_spoof_app_version_target_entry_1 @string/revanced_spoof_app_version_target_entry_2 @string/revanced_spoof_app_version_target_entry_3 - @string/revanced_spoof_app_version_target_entry_4 - @string/revanced_spoof_app_version_target_entry_5 - @string/revanced_spoof_app_version_target_entry_6 18.33.40 18.20.39 18.09.39 - 17.08.35 - 16.08.35 - 16.01.35 diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index fbda6995..746cd9be 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -786,9 +786,6 @@ 18.33.40 - Restore RYD Shorts incognito mode 18.20.39 - Restore wide video speed & quality menu 18.09.39 - Restore library tab - 17.08.35 - Restore old UI layout - 16.08.35 - Restore explore tab - 16.01.35 - Restore fewer video player action buttons Set start page From c22604a7267609c39572236d38822f1e083d3fd7 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Thu, 29 Feb 2024 00:18:20 +0000 Subject: [PATCH 42/52] chore(release): 4.3.0-dev.10 [skip ci] # [4.3.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.9...v4.3.0-dev.10) (2024-02-29) ### Bug Fixes * **YouTube - Spoof app version:** Remove broken versions ([#2776](https://github.com/ReVanced/revanced-patches/issues/2776)) ([9466d97](https://github.com/ReVanced/revanced-patches/commit/9466d973c6d7a2891e3fa9f283107b64399152ea)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c71e3521..88ceb007 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.9...v4.3.0-dev.10) (2024-02-29) + + +### Bug Fixes + +* **YouTube - Spoof app version:** Remove broken versions ([#2776](https://github.com/ReVanced/revanced-patches/issues/2776)) ([9466d97](https://github.com/ReVanced/revanced-patches/commit/9466d973c6d7a2891e3fa9f283107b64399152ea)) + # [4.3.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.8...v4.3.0-dev.9) (2024-02-28) diff --git a/gradle.properties b/gradle.properties index c090138a..9b57eb46 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.9 +version = 4.3.0-dev.10 From bcd8b48e70693dac1bfcc0bf4971d6b526065b59 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 2 Mar 2024 08:03:07 +0100 Subject: [PATCH 43/52] fix(YouTube - Spoof signature): Fix tracking such as history or watch time --- .../misc/fix/playback/SpoofSignaturePatch.kt | 77 ++++++++++++++----- .../fingerprints/ParamsMapPutFingerprint.kt | 24 ++++++ .../StatsQueryParameterFingerprint.kt | 7 ++ 3 files changed, 88 insertions(+), 20 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt index 0bcfcf27..25c31d66 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt @@ -16,7 +16,8 @@ import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch -import app.revanced.util.exception +import app.revanced.util.* +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -28,8 +29,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction PlayerResponseMethodHookPatch::class, VideoInformationPatch::class, SpoofSignatureResourcePatch::class, - AddResourcesPatch::class - ] + AddResourcesPatch::class, + ], ) object SpoofSignaturePatch : BytecodePatch( setOf( @@ -41,7 +42,9 @@ object SpoofSignaturePatch : BytecodePatch( StoryboardRendererDecoderRecommendedLevelFingerprint, StoryboardThumbnailParentFingerprint, ScrubbedPreviewLayoutFingerprint, - ) + StatsQueryParameterFingerprint, + ParamsMapPutFingerprint, + ), ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/spoof/SpoofSignaturePatch;" @@ -55,14 +58,14 @@ object SpoofSignaturePatch : BytecodePatch( preferences = setOf( SwitchPreference("revanced_spoof_signature_verification_enabled"), SwitchPreference("revanced_spoof_signature_in_feed_enabled"), - SwitchPreference("revanced_spoof_storyboard") + SwitchPreference("revanced_spoof_storyboard"), ), - ) + ), ) // Hook the player parameters. PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter( - "$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Z)Ljava/lang/String;" + "$INTEGRATIONS_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Z)Ljava/lang/String;", ) // Force the seekbar time and chapters to always show up. @@ -72,7 +75,7 @@ object SpoofSignaturePatch : BytecodePatch( StoryboardThumbnailFingerprint.also { it.resolve( context, - classDef + classDef, ) }.result?.let { val endIndex = it.scanResult.patternScanResult!!.endIndex @@ -84,7 +87,7 @@ object SpoofSignaturePatch : BytecodePatch( endIndex, """ invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarThumbnailOverrideValue()Z - """ + """, ) // Since this is end of the method must replace one line then add the rest. it.mutableMethod.addInstructions( @@ -92,7 +95,7 @@ object SpoofSignaturePatch : BytecodePatch( """ move-result v0 return v0 - """ + """, ) } ?: throw StoryboardThumbnailFingerprint.exception } @@ -107,7 +110,7 @@ object SpoofSignaturePatch : BytecodePatch( """ iget-object v0, p0, $imageViewFieldName # copy imageview field to a register invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->seekbarImageViewCreated(Landroid/widget/ImageView;)V - """ + """, ) } } ?: throw ScrubbedPreviewLayoutFingerprint.exception @@ -117,7 +120,7 @@ object SpoofSignaturePatch : BytecodePatch( */ arrayOf( PlayerResponseModelImplGeneralFingerprint, - PlayerResponseModelImplLiveStreamFingerprint + PlayerResponseModelImplLiveStreamFingerprint, ).forEach { fingerprint -> fingerprint.result?.let { it.mutableMethod.apply { @@ -130,7 +133,7 @@ object SpoofSignaturePatch : BytecodePatch( """ invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; move-result-object v$getStoryBoardRegister - """ + """, ) } } ?: throw fingerprint.exception @@ -143,10 +146,11 @@ object SpoofSignaturePatch : BytecodePatch( .getInstruction(moveOriginalRecommendedValueIndex).registerA it.mutableMethod.addInstructions( - moveOriginalRecommendedValueIndex + 1, """ + moveOriginalRecommendedValueIndex + 1, + """ invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I move-result v$originalValueRegister - """ + """, ) } ?: throw StoryboardRendererDecoderRecommendedLevelFingerprint.exception @@ -158,10 +162,11 @@ object SpoofSignaturePatch : BytecodePatch( getInstruction(moveOriginalRecommendedValueIndex).registerA addInstructions( - moveOriginalRecommendedValueIndex, """ + moveOriginalRecommendedValueIndex, + """ invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I move-result v$originalValueRegister - """ + """, ) } } ?: throw PlayerResponseModelImplRecommendedLevelFingerprint.exception @@ -177,7 +182,7 @@ object SpoofSignaturePatch : BytecodePatch( invoke-static { p$storyBoardUrlParams }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; move-result-object p$storyBoardUrlParams """, - ExternalLabel("ignore", getInstruction(0)) + ExternalLabel("ignore", getInstruction(0)), ) } } ?: throw StoryboardRendererSpecFingerprint.exception @@ -189,11 +194,43 @@ object SpoofSignaturePatch : BytecodePatch( it.mutableMethod.getInstruction(storyBoardUrlIndex).registerA it.mutableMethod.addInstructions( - storyBoardUrlIndex + 1, """ + storyBoardUrlIndex + 1, + """ invoke-static { v$storyboardUrlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardDecoderRendererSpec(Ljava/lang/String;)Ljava/lang/String; move-result-object v$storyboardUrlRegister - """ + """, ) } ?: throw StoryboardRendererDecoderSpecFingerprint.exception + + // Fix stats not being tracked. + // Due to signature spoofing "adformat" is present in query parameters made for /stats requests, + // even though, for regular videos, it should not be. + // This breaks stats tracking. + // Replace the ad parameter with the video parameter in the query parameters. + StatsQueryParameterFingerprint.result?.let { + val putMethod = ParamsMapPutFingerprint.result?.method?.toString() + ?: throw ParamsMapPutFingerprint.exception + + it.mutableMethod.apply { + val adParamIndex = it.scanResult.stringsScanResult!!.matches.first().index + val videoParamIndex = adParamIndex + 3 + + // Replace the ad parameter with the video parameter. + replaceInstruction(adParamIndex, getInstruction(videoParamIndex)) + + // Call paramsMap.put instead of paramsMap.putIfNotExist + // because the key is already present in the map. + val putAdParamIndex = adParamIndex + 1 + val putIfKeyNotExistsInstruction = getInstruction(putAdParamIndex) + replaceInstruction( + putAdParamIndex, + "invoke-virtual { " + + "v${putIfKeyNotExistsInstruction.registerC}, " + + "v${putIfKeyNotExistsInstruction.registerD}, " + + "v${putIfKeyNotExistsInstruction.registerE} }, " + + putMethod, + ) + } + } ?: throw StatsQueryParameterFingerprint.exception } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt new file mode 100644 index 00000000..1a60c306 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +internal object ParamsMapPutFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf( + "Ljava/lang/String;", + "Ljava/lang/String;", + ), + opcodes = listOf( + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.INVOKE_DIRECT_RANGE, + ), +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt new file mode 100644 index 00000000..a9cc5304 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object StatsQueryParameterFingerprint : MethodFingerprint( + strings = listOf("adunit"), +) From 2d53037847d4833c1f8830d40cdee685f007a7d0 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 2 Mar 2024 07:05:33 +0000 Subject: [PATCH 44/52] chore(release): 4.3.0-dev.11 [skip ci] # [4.3.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.10...v4.3.0-dev.11) (2024-03-02) ### Bug Fixes * **YouTube - Spoof signature:** Fix tracking such as history or watch time ([bcd8b48](https://github.com/ReVanced/revanced-patches/commit/bcd8b48e70693dac1bfcc0bf4971d6b526065b59)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 88ceb007..e6fd1bce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.10...v4.3.0-dev.11) (2024-03-02) + + +### Bug Fixes + +* **YouTube - Spoof signature:** Fix tracking such as history or watch time ([bcd8b48](https://github.com/ReVanced/revanced-patches/commit/bcd8b48e70693dac1bfcc0bf4971d6b526065b59)) + # [4.3.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.9...v4.3.0-dev.10) (2024-02-29) diff --git a/gradle.properties b/gradle.properties index 9b57eb46..aea373cd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.10 +version = 4.3.0-dev.11 From 83a7bd8d69e62623fc4d2ba73d9fb49e92751d89 Mon Sep 17 00:00:00 2001 From: kitadai31 <90122968+kitadai31@users.noreply.github.com> Date: Sat, 2 Mar 2024 16:10:07 +0900 Subject: [PATCH 45/52] feat(YouTube - Spoof app version): Add target versions (#2787) --- src/main/resources/addresources/values/arrays.xml | 4 ++++ src/main/resources/addresources/values/strings.xml | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/resources/addresources/values/arrays.xml b/src/main/resources/addresources/values/arrays.xml index 908b80ee..064dcd05 100644 --- a/src/main/resources/addresources/values/arrays.xml +++ b/src/main/resources/addresources/values/arrays.xml @@ -5,11 +5,15 @@ @string/revanced_spoof_app_version_target_entry_1 @string/revanced_spoof_app_version_target_entry_2 @string/revanced_spoof_app_version_target_entry_3 + @string/revanced_spoof_app_version_target_entry_4 + @string/revanced_spoof_app_version_target_entry_5 18.33.40 18.20.39 18.09.39 + 17.41.37 + 17.33.42 diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 746cd9be..390750d1 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -783,9 +783,11 @@ Version not spoofed App version will be spoofed to an older version of YouTube.\n\nThis will change the appearance and features of the app, but unknown side effects may occur.\n\nIf later turned off, it is recommended to clear the app data to prevent UI bugs. Spoof app version target - 18.33.40 - Restore RYD Shorts incognito mode + 18.33.40 - Restore RYD on Shorts incognito mode 18.20.39 - Restore wide video speed & quality menu 18.09.39 - Restore library tab + 17.41.37 - Restore old playlist shelf + 17.33.42 - Restore old UI layout Set start page From 0342c79c177fbd316d191a6e5bc6b9bce9d1f94d Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 2 Mar 2024 07:12:52 +0000 Subject: [PATCH 46/52] chore(release): 4.3.0-dev.12 [skip ci] # [4.3.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.11...v4.3.0-dev.12) (2024-03-02) ### Features * **YouTube - Spoof app version:** Add target versions ([#2787](https://github.com/ReVanced/revanced-patches/issues/2787)) ([83a7bd8](https://github.com/ReVanced/revanced-patches/commit/83a7bd8d69e62623fc4d2ba73d9fb49e92751d89)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6fd1bce..c64506ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.11...v4.3.0-dev.12) (2024-03-02) + + +### Features + +* **YouTube - Spoof app version:** Add target versions ([#2787](https://github.com/ReVanced/revanced-patches/issues/2787)) ([83a7bd8](https://github.com/ReVanced/revanced-patches/commit/83a7bd8d69e62623fc4d2ba73d9fb49e92751d89)) + # [4.3.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.10...v4.3.0-dev.11) (2024-03-02) diff --git a/gradle.properties b/gradle.properties index aea373cd..82b7515e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.11 +version = 4.3.0-dev.12 From 36132df4be6a04c08b6f3dd79de1bcea93a80fb8 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sat, 2 Mar 2024 11:27:05 +0400 Subject: [PATCH 47/52] feat(YouTube): Reorganize settings menu (#2737) Co-authored-by: oSumAtrIX Co-authored-by: semantic-release-bot Co-authored-by: dic1911 --- api/revanced-patches.api | 30 ++- .../reddit/ad/comments/HideCommentAdsPatch.kt | 2 +- .../piracy/DisablePiracyDetectionPatch.kt | 11 +- .../settings/BaseSettingsResourcePatch.kt | 12 +- .../preference/BasePreferenceScreen.kt | 34 ++- .../settings/preference/IntentPreference.kt | 7 +- .../preference/NonInteractivePreference.kt | 6 +- .../settings/preference/PreferenceScreen.kt | 34 ++- .../patches/twitch/ad/audio/AudioAdsPatch.kt | 4 +- .../patches/twitch/ad/video/VideoAdsPatch.kt | 4 +- .../patches/twitch/debug/DebugModePatch.kt | 4 +- .../twitch/misc/settings/SettingsPatch.kt | 5 +- .../ad/general/HideAdsResourcePatch.kt | 3 +- .../ad/getpremium/HideGetPremiumPatch.kt | 4 +- .../patches/youtube/ad/video/VideoAdsPatch.kt | 4 +- .../copyvideourl/CopyVideoUrlResourcePatch.kt | 14 +- .../RemoveViewerDiscretionDialogPatch.kt | 4 +- .../ExternalDownloadsResourcePatch.kt | 14 +- .../DisablePreciseSeekingGesturePatch.kt | 2 +- .../seekbar/EnableSeekbarTappingPatch.kt | 4 +- .../seekbar/EnableSlideToSeekPatch.kt | 4 +- .../SwipeControlsResourcePatch.kt | 32 ++- .../layout/autocaptions/AutoCaptionsPatch.kt | 4 +- .../branding/header/ChangeHeaderPatch.kt | 2 +- .../layout/buttons/action/HideButtonsPatch.kt | 5 +- .../autoplay/HideAutoplayButtonPatch.kt | 4 +- .../captions/HideCaptionsButtonPatch.kt | 4 +- .../buttons/cast/HideCastButtonPatch.kt | 4 +- .../navigation/NavigationButtonsPatch.kt | 43 ++-- .../player/hide/HidePlayerButtonsPatch.kt | 4 +- .../albumcards/AlbumCardsResourcePatch.kt | 4 +- .../breakingnews/BreakingNewsResourcePatch.kt | 4 +- .../layout/hide/comments/CommentsPatch.kt | 4 +- .../CrowdfundingBoxResourcePatch.kt | 4 +- .../HideEndscreenCardsResourcePatch.kt | 4 +- .../filterbar/HideFilterBarResourcePatch.kt | 4 +- ...deFloatingMicrophoneButtonResourcePatch.kt | 4 +- .../DisableFullscreenAmbientModePatch.kt | 2 +- .../hide/general/HideLayoutComponentsPatch.kt | 115 +++++---- .../infocards/HideInfocardsResourcePatch.kt | 4 +- .../HideLoadMoreButtonResourcePatch.kt | 4 +- .../HideEmailAddressPatch.kt | 0 .../HidePlayerFlyoutMenuPatch.kt | 2 +- .../DisableRollingNumberAnimationPatch.kt | 2 +- .../layout/hide/seekbar/HideSeekbarPatch.kt | 4 +- .../HideShortsComponentsResourcePatch.kt | 32 ++- ...bleSuggestedVideoEndScreenResourcePatch.kt | 2 +- .../layout/hide/time/HideTimestampPatch.kt | 4 +- .../panels/popup/PlayerPopupPanelsPatch.kt | 4 +- ...CustomPlayerOverlayOpacityResourcePatch.kt | 2 +- .../ReturnYouTubeDislikeResourcePatch.kt | 13 +- .../layout/searchbar/WideSearchbarPatch.kt | 4 +- .../RestoreOldSeekbarThumbnailsPatch.kt | 7 +- .../layout/seekbar/SeekbarPreferencesPatch.kt | 34 --- .../sponsorblock/SponsorBlockResourcePatch.kt | 12 +- .../spoofappversion/SpoofAppVersionPatch.kt | 2 +- .../layout/startpage/ChangeStartPagePatch.kt | 2 +- .../DisableResumingShortsOnStartupPatch.kt | 2 +- .../layout/tablet/EnableTabletLayoutPatch.kt | 4 +- .../tabletminiplayer/TabletMiniPlayerPatch.kt | 6 +- .../layout/theme/ThemeBytecodePatch.kt | 4 +- .../layout/theme/ThemeResourcePatch.kt | 4 +- .../thumbnails/AlternativeThumbnailsPatch.kt | 85 +++---- .../AlternativeThumbnailsResourcePatch.kt | 19 -- .../misc/announcements/AnnouncementsPatch.kt | 4 +- .../misc/autorepeat/AutoRepeatPatch.kt | 4 +- .../youtube/misc/debugging/DebuggingPatch.kt | 12 +- .../spoof/SpoofDeviceDimensionsPatch.kt | 4 +- .../misc/fix/playback/SpoofSignaturePatch.kt | 14 +- .../misc/links/BypassURLRedirectsPatch.kt | 4 +- .../misc/links/OpenLinksExternallyPatch.kt | 4 +- .../MinimizedPlaybackPatch.kt | 8 +- .../RemoveTrackingQueryParameterPatch.kt | 4 +- .../youtube/misc/settings/SettingsPatch.kt | 84 +++++-- .../misc/settings/SettingsResourcePatch.kt | 26 ++- .../misc/zoomhaptics/ZoomHapticsPatch.kt | 4 +- .../video/hdrbrightness/HDRBrightnessPatch.kt | 4 +- .../resources/addresources/values/strings.xml | 218 ++++++++---------- .../layout/revanced_settings_with_toolbar.xml | 2 +- .../resources/settings/xml/revanced_prefs.xml | 4 +- 80 files changed, 606 insertions(+), 505 deletions(-) delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarPreferencesPatch.kt delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsResourcePatch.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index e380e87b..f0d4cd1a 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -723,10 +723,8 @@ public abstract class app/revanced/patches/shared/misc/settings/preference/BaseP } public class app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$BasePreferenceCollection { - public fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;)V - public synthetic fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;)V - public synthetic fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;)V + public synthetic fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun addPreferences ([Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V public final fun getCategories ()Ljava/util/Set; public synthetic fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreference; @@ -798,12 +796,22 @@ public class app/revanced/patches/shared/misc/settings/preference/PreferenceCate } public class app/revanced/patches/shared/misc/settings/preference/PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreference { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;Ljava/lang/String;Ljava/util/Set;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getPreferences ()Ljava/util/Set; public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } +public final class app/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting : java/lang/Enum { + public static final field BY_KEY Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting; + public static final field BY_TITLE Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting; + public static final field UNSORTED Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun getKeySuffix ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting; + public static fun values ()[Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen$Sorting; +} + public final class app/revanced/patches/shared/misc/settings/preference/SummaryType : java/lang/Enum { public static final field DEFAULT Lapp/revanced/patches/shared/misc/settings/preference/SummaryType; public static final field OFF Lapp/revanced/patches/shared/misc/settings/preference/SummaryType; @@ -1468,7 +1476,6 @@ public final class app/revanced/patches/youtube/layout/tabletminiplayer/TabletMi public static final field INSTANCE Lapp/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V - public final fun unwrap (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lkotlin/Triple; } public final class app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch : app/revanced/patcher/patch/BytecodePatch { @@ -1617,9 +1624,14 @@ public final class app/revanced/patches/youtube/misc/settings/SettingsPatch$Pref public static final field INSTANCE Lapp/revanced/patches/youtube/misc/settings/SettingsPatch$PreferenceScreen; public fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen;)V public final fun getADS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; - public final fun getINTERACTIONS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; - public final fun getLAYOUT ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getALTERNATIVE_THUMBNAILS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getFEED ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getGENERAL_LAYOUT ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; public final fun getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getPLAYER ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getSEEKBAR ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getSHORTS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getSWIPE_CONTROLS ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; public final fun getVIDEO ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; } diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt index 298f7017..fa1ad21a 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/ad/comments/HideCommentAdsPatch.kt @@ -7,7 +7,7 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.reddit.ad.comments.fingerprints.HideCommentAdsFingerprint -@Patch(description = "Removes ads in the comments.",) +@Patch(description = "Removes ads in the comments.") object HideCommentAdsPatch : BytecodePatch( setOf(HideCommentAdsFingerprint) ) { diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/detection/piracy/DisablePiracyDetectionPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/detection/piracy/DisablePiracyDetectionPatch.kt index e075ee69..f941550b 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/detection/piracy/DisablePiracyDetectionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/syncforreddit/detection/piracy/DisablePiracyDetectionPatch.kt @@ -6,18 +6,13 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.reddit.customclients.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint -@Patch(description = "Disables detection of modified versions.",) +@Patch(description = "Disables detection of modified versions.") object DisablePiracyDetectionPatch : BytecodePatch(setOf(PiracyDetectionFingerprint)) { override fun execute(context: BytecodeContext) { // Do not throw an error if the fingerprint is not resolved. // This is fine because new versions of the target app do not need this patch. PiracyDetectionFingerprint.result?.mutableMethod?.apply { - addInstruction( - 0, - """ - return-void - """ - ) + addInstruction(0, "return-void") } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt index 8af71dfe..f1e48837 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt @@ -41,12 +41,18 @@ abstract class BaseSettingsResourcePatch( } override fun close() { - fun Node.addPreference(preference: BasePreference) { + fun Node.addPreference(preference: BasePreference, prepend: Boolean = false) { preference.serialize(ownerDocument) { resource -> // TODO: Currently, resources can only be added to "values", which may not be the correct place. // It may be necessary to ask for the desired resourceValue in the future. AddResourcesPatch("values", resource) - }.let(this::appendChild) + }.let { preferenceNode -> + if (prepend && firstChild != null) { + insertBefore(preferenceNode, firstChild) + } else { + appendChild(preferenceNode) + } + } } // Add the root preference to an existing fragment if needed. @@ -54,7 +60,7 @@ abstract class BaseSettingsResourcePatch( context.xmlEditor["res/xml/$fragment.xml"].use { editor -> val document = editor.file - document.getNode("PreferenceScreen").addPreference(intentPreference) + document.getNode("PreferenceScreen").addPreference(intentPreference, true) } } diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen.kt index 29bf976a..381a2cf3 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen.kt @@ -1,9 +1,10 @@ package app.revanced.patches.shared.misc.settings.preference +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import java.io.Closeable abstract class BasePreferenceScreen( - private val root: MutableSet = mutableSetOf() + private val root: MutableSet = mutableSetOf(), ) : Closeable { override fun close() { @@ -24,33 +25,27 @@ abstract class BasePreferenceScreen( titleKey: String = "${key}_title", private val summaryKey: String? = "${key}_summary", preferences: MutableSet = mutableSetOf(), - val categories: MutableSet = mutableSetOf() + val categories: MutableSet = mutableSetOf(), + private val sorting: Sorting = Sorting.BY_TITLE, ) : BasePreferenceCollection(key, titleKey, preferences) { - /** - * Initialize using title and summary keys with suffix "_title" and "_summary". - */ - constructor( - key: String? = null, - preferences: MutableSet = mutableSetOf(), - categories: MutableSet = mutableSetOf() - ) : this(key, key + "_title", key + "_summary", preferences, categories) - override fun transform(): PreferenceScreen { return PreferenceScreen( key, titleKey, summaryKey, + sorting, // Screens and preferences are sorted at runtime by integrations code, - // so they appear in alphabetical order for the localized language in use. - preferences = preferences + categories.map { it.transform() } + // so title sorting uses the localized language in use. + preferences = preferences + categories.map { it.transform() }, ) } private fun ensureScreenInserted() { // Add to screens if not yet done - if (!root.contains(this)) + if (!root.contains(this)) { root.add(this) + } } fun addPreferences(vararg preferences: BasePreference) { @@ -61,13 +56,13 @@ abstract class BasePreferenceScreen( open inner class Category( key: String? = null, titleKey: String = "${key}_title", - preferences: MutableSet = mutableSetOf() + preferences: MutableSet = mutableSetOf(), ) : BasePreferenceCollection(key, titleKey, preferences) { override fun transform(): PreferenceCategory { return PreferenceCategory( key, titleKey, - preferences = preferences + preferences = preferences, ) } @@ -75,8 +70,9 @@ abstract class BasePreferenceScreen( ensureScreenInserted() // Add to the categories if not done yet. - if (!categories.contains(this)) + if (!categories.contains(this)) { categories.add(this) + } this.preferences.addAll(preferences) } @@ -86,8 +82,8 @@ abstract class BasePreferenceScreen( abstract class BasePreferenceCollection( val key: String? = null, val titleKey: String = "${key}_title", - val preferences: MutableSet = mutableSetOf() + val preferences: MutableSet = mutableSetOf(), ) { abstract fun transform(): BasePreference } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/IntentPreference.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/IntentPreference.kt index 3c933a72..dbc109ae 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/IntentPreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/IntentPreference.kt @@ -1,19 +1,16 @@ package app.revanced.patches.shared.misc.settings.preference -import app.revanced.patches.shared.misc.settings.preference.IntentPreference.Intent import app.revanced.util.resource.BaseResource import org.w3c.dom.Document /** * A preference that opens an intent. * - * @param key The preference key. If null, other parameters must be specified. + * @param key Optional preference key. * @param titleKey The preference title key. * @param summaryKey The preference summary key. * @param tag The preference tag. * @param intent The intent to open. - * - * @see Intent */ class IntentPreference( key: String? = null, @@ -21,7 +18,7 @@ class IntentPreference( summaryKey: String? = "${key}_summary", tag: String = "Preference", val intent: Intent, -) : BasePreference(null, titleKey, summaryKey, tag) { +) : BasePreference(key, titleKey, summaryKey, tag) { override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = super.serialize(ownerDocument, resourceCallback).apply { diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference.kt index b4b9155a..f9525f92 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference.kt @@ -6,10 +6,12 @@ import org.w3c.dom.Document /** * A non-interactive preference. * + * Typically used to present static text, but also used for custom integration code that responds to taps. + * * @param key The preference key. * @param summaryKey The preference summary key. - * @param tag The preference tag. - * @param selectable Whether the preference is selectable. + * @param tag The tag or full class name of the preference. + * @param selectable If the preference is selectable and responds to tap events. */ @Suppress("MemberVisibilityCanBePrivate") class NonInteractivePreference( diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceScreen.kt index f03dd23a..049966a2 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceScreen.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceScreen.kt @@ -9,6 +9,8 @@ import org.w3c.dom.Document * @param key The key of the preference. If null, other parameters must be specified. * @param titleKey The key of the preference title. * @param summaryKey The key of the preference summary. + * @param sorting Sorting to use. If the sorting is not [Sorting.UNSORTED], + * then the key parameter will be modified to include the sort type. * @param tag The tag or full class name of the preference. * @param preferences The preferences in this screen. */ @@ -17,14 +19,40 @@ open class PreferenceScreen( key: String? = null, titleKey: String = "${key}_title", summaryKey: String? = "${key}_summary", + sorting: Sorting = Sorting.BY_TITLE, tag: String = "PreferenceScreen", - val preferences: Set -) : BasePreference(key, titleKey, summaryKey, tag) { - + val preferences: Set, + // Alternatively, instead of repurposing the key for sorting, + // an extra bundle parameter can be added to the preferences XML declaration. + // This would require bundling and referencing an additional XML file + // or adding new attributes to the attrs.xml file. + // Since the key value is not currently used by integrations, + // for now it's much simpler to modify the key to include the sort parameter. +) : BasePreference(if (sorting == Sorting.UNSORTED) key else (key + sorting.keySuffix), titleKey, summaryKey, tag) { override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = super.serialize(ownerDocument, resourceCallback).apply { preferences.forEach { appendChild(it.serialize(ownerDocument, resourceCallback)) } } + + /** + * How a PreferenceScreen should be sorted. + */ + enum class Sorting(val keySuffix: String) { + /** + * Sort by the localized preference title. + */ + BY_TITLE("_sort_by_title"), + + /** + * Sort by the preference keys. + */ + BY_KEY("_sort_by_key"), + + /** + * Unspecified sorting. + */ + UNSORTED("_sort_by_unsorted"), + } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt index 75f9df43..31b398ca 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/AudioAdsPatch.kt @@ -26,7 +26,9 @@ object AudioAdsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(SwitchPreference("revanced_block_audio_ads")) + SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( + SwitchPreference("revanced_block_audio_ads") + ) // Block playAds call with(AudioAdsPresenterPlayFingerprint.result!!) { diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt index ab00fe79..c238c491 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/video/VideoAdsPatch.kt @@ -35,7 +35,9 @@ object VideoAdsPatch : BaseAdPatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(SwitchPreference("revanced_block_video_ads")) + SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( + SwitchPreference("revanced_block_video_ads") + ) /* Amazon ads SDK */ context.blockMethods( diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt index 644b614c..ad595c9e 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt @@ -32,7 +32,9 @@ object DebugModePatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences(SwitchPreference("revanced_twitch_debug_mode")) + SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences( + SwitchPreference("revanced_twitch_debug_mode") + ) listOf( IsDebugConfigEnabledFingerprint, diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt index e8ec635c..719c6559 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsPatch.kt @@ -25,7 +25,6 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.immutable.ImmutableField import java.io.Closeable - @Patch( name = "Settings", description = "Adds settings menu to Twitch.", @@ -62,7 +61,9 @@ object SettingsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - PreferenceScreen.MISC.OTHER.addPreferences(SwitchPreference("revanced_debug")) + PreferenceScreen.MISC.OTHER.addPreferences( + SwitchPreference("revanced_debug") + ) // Hook onCreate to handle fragment creation SettingsActivityOnCreateFingerprint.result?.apply { diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt index d7c3a359..c89ba7ec 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsResourcePatch.kt @@ -8,7 +8,6 @@ import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.patches.youtube.misc.settings.SettingsPatch.PreferenceScreen @Patch( dependencies = [ @@ -27,7 +26,7 @@ object HideAdsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - PreferenceScreen.ADS.addPreferences( + SettingsPatch.PreferenceScreen.ADS.addPreferences( SwitchPreference("revanced_hide_general_ads"), SwitchPreference("revanced_hide_fullscreen_ads"), SwitchPreference("revanced_hide_buttoned_ads"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt index 24cb84a8..5cc676ff 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/getpremium/HideGetPremiumPatch.kt @@ -44,7 +44,9 @@ object HideGetPremiumPatch : BytecodePatch(setOf(GetPremiumViewFingerprint)) { override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.ADS.addPreferences(SwitchPreference("revanced_hide_get_premium")) + SettingsPatch.PreferenceScreen.ADS.addPreferences( + SwitchPreference("revanced_hide_get_premium") + ) GetPremiumViewFingerprint.result?.let { it.mutableMethod.apply { diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt index bface060..d03c3ff2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/VideoAdsPatch.kt @@ -49,7 +49,9 @@ object VideoAdsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.ADS.addPreferences(SwitchPreference("revanced_hide_video_ads")) + SettingsPatch.PreferenceScreen.ADS.addPreferences( + SwitchPreference("revanced_hide_video_ads") + ) val loadVideoAdsFingerprintMethod = LoadVideoAdsFingerprint.result!!.mutableMethod diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlResourcePatch.kt index 83a44568..23476080 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlResourcePatch.kt @@ -4,7 +4,6 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -22,14 +21,9 @@ internal object CopyVideoUrlResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - PreferenceScreen( - "revanced_copy_video_url_preference_screen", - preferences = setOf( - SwitchPreference("revanced_copy_video_url"), - SwitchPreference("revanced_copy_video_url_timestamp") - ) - ) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_copy_video_url"), + SwitchPreference("revanced_copy_video_url_timestamp") ) context.copyResources( @@ -40,8 +34,6 @@ internal object CopyVideoUrlResourcePatch : ResourcePatch() { ) ) - AddResourcesPatch(this::class) - BottomControlsResourcePatch.addControls("copyvideourl") } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt index e67cdb9f..591e16bf 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/dialog/RemoveViewerDiscretionDialogPatch.kt @@ -50,7 +50,9 @@ object RemoveViewerDiscretionDialogPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_remove_viewer_discretion_dialog")) + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_remove_viewer_discretion_dialog") + ) CreateDialogFingerprint.result?.mutableMethod?.apply { val showDialogIndex = implementation!!.instructions.lastIndex - 2 diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt index 656eb13d..e24b7e6c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt @@ -6,6 +6,7 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.misc.playercontrols.BottomControlsResourcePatch @@ -18,25 +19,26 @@ import app.revanced.util.copyResources BottomControlsResourcePatch::class, SettingsPatch::class, AddResourcesPatch::class, - ] + ], ) internal object ExternalDownloadsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( PreferenceScreen( - "revanced_external_downloader_preference_screen", + key = "revanced_external_downloader_screen", + sorting = Sorting.UNSORTED, preferences = setOf( SwitchPreference("revanced_external_downloader"), - TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT) + TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT), ), - ) + ), ) context.copyResources( "downloads", - ResourceGroup("drawable", "revanced_yt_download_button.xml") + ResourceGroup("drawable", "revanced_yt_download_button.xml"), ) BottomControlsResourcePatch.addControls("downloads") diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt index 6aebf707..a7cbd0a7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/DisablePreciseSeekingGesturePatch.kt @@ -50,7 +50,7 @@ object DisablePreciseSeekingGesturePatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( SwitchPreference("revanced_disable_precise_seeking_gesture") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt index ed67a5eb..0b11595d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSeekbarTappingPatch.kt @@ -51,7 +51,9 @@ object EnableSeekbarTappingPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_seekbar_tapping")) + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( + SwitchPreference("revanced_seekbar_tapping") + ) // Find the required methods to tap the seekbar. val seekbarTappingMethods = OnTouchEventHandlerFingerprint.result?.let { diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt index f5dd14ad..ec38b7e7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt @@ -50,7 +50,9 @@ object EnableSlideToSeekPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_slide_to_seek")) + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( + SwitchPreference("revanced_slide_to_seek") + ) arrayOf( // Restore the behaviour to slide to seek. diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsResourcePatch.kt index de615456..70fe6e50 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsResourcePatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.InputType -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -13,27 +12,22 @@ import app.revanced.util.ResourceGroup import app.revanced.util.copyResources @Patch( - dependencies = [SettingsPatch::class, AddResourcesPatch::class] + dependencies = [SettingsPatch::class, AddResourcesPatch::class], ) internal object SwipeControlsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - PreferenceScreen( - key = "revanced_swipe_controls_preference_screen", - preferences = setOf( - SwitchPreference("revanced_swipe_brightness"), - SwitchPreference("revanced_swipe_volume"), - SwitchPreference("revanced_swipe_press_to_engage"), - SwitchPreference("revanced_swipe_haptic_feedback"), - SwitchPreference("revanced_swipe_save_and_restore_brightness"), - TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER), - TextPreference("revanced_swipe_text_overlay_size", inputType = InputType.NUMBER), - TextPreference("revanced_swipe_overlay_background_alpha", inputType = InputType.NUMBER), - TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER) - ), - ) + SettingsPatch.PreferenceScreen.SWIPE_CONTROLS.addPreferences( + SwitchPreference("revanced_swipe_brightness"), + SwitchPreference("revanced_swipe_volume"), + SwitchPreference("revanced_swipe_press_to_engage"), + SwitchPreference("revanced_swipe_haptic_feedback"), + SwitchPreference("revanced_swipe_save_and_restore_brightness"), + TextPreference("revanced_swipe_overlay_timeout", inputType = InputType.NUMBER), + TextPreference("revanced_swipe_text_overlay_size", inputType = InputType.NUMBER), + TextPreference("revanced_swipe_overlay_background_alpha", inputType = InputType.NUMBER), + TextPreference("revanced_swipe_threshold", inputType = InputType.NUMBER), ) context.copyResources( @@ -43,8 +37,8 @@ internal object SwipeControlsResourcePatch : ResourcePatch() { "revanced_ic_sc_brightness_auto.xml", "revanced_ic_sc_brightness_manual.xml", "revanced_ic_sc_volume_mute.xml", - "revanced_ic_sc_volume_normal.xml" - ) + "revanced_ic_sc_volume_normal.xml", + ), ) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt index 80d33fd6..6afc7290 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/AutoCaptionsPatch.kt @@ -48,7 +48,9 @@ object AutoCaptionsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_auto_captions")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_auto_captions") + ) mapOf( StartVideoInformerFingerprint to 0, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt index 96f8a22a..d0614297 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -82,7 +82,7 @@ object ChangeHeaderPatch : ResourcePatch() { } /** - * A function that overwrites both header variants from [from] to [to] in the target resource directories. + * A function that overwrites both header variants in the target resource directories. */ val overwriteFromTo: (String, String) -> Unit = { from: String, to: String -> targetResourceDirectories.forEach { directory -> diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt index ca9c19de..6debdf1a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/HideButtonsPatch.kt @@ -48,12 +48,11 @@ object HideButtonsPatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( PreferenceScreen( - "revanced_hide_buttons_preference_screen", + "revanced_hide_buttons_screen", preferences = setOf( SwitchPreference("revanced_hide_like_dislike_button"), - SwitchPreference("revanced_hide_live_chat_button"), SwitchPreference("revanced_hide_share_button"), SwitchPreference("revanced_hide_report_button"), SwitchPreference("revanced_hide_remix_button"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt index 79ee7e6a..5937185e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/HideAutoplayButtonPatch.kt @@ -57,7 +57,9 @@ object HideAutoplayButtonPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_autoplay_button")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_autoplay_button") + ) LayoutConstructorFingerprint.result?.mutableMethod?.apply { val layoutGenMethodInstructions = implementation!!.instructions diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt index 45fe579f..a9f2b9f7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/HideCaptionsButtonPatch.kt @@ -48,7 +48,9 @@ object HideCaptionsButtonPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_captions_button")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_captions_button") + ) val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt index 24dda9fd..aaec9870 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/HideCastButtonPatch.kt @@ -27,7 +27,9 @@ object HideCastButtonPatch : BytecodePatch(emptySet()) { override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_cast_button")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_cast_button") + ) val buttonClass = context.findClass("MediaRouteButton") ?: throw PatchException("MediaRouteButton class not found.") diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt index 71e7374d..a8ac8121 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/NavigationButtonsPatch.kt @@ -8,6 +8,7 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.* import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT @@ -24,7 +25,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction IntegrationsPatch::class, SettingsPatch::class, ResolvePivotBarFingerprintsPatch::class, - AddResourcesPatch::class + AddResourcesPatch::class, ], compatiblePackages = [ CompatiblePackage( @@ -42,14 +43,14 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) - ] + "19.04.37", + ], + ), + ], ) @Suppress("unused") object NavigationButtonsPatch : BytecodePatch( - setOf(AddCreateButtonViewFingerprint) + setOf(AddCreateButtonViewFingerprint), ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;" @@ -57,17 +58,18 @@ object NavigationButtonsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( PreferenceScreen( - key = "revanced_navigation_buttons_preference_screen", + key = "revanced_navigation_buttons_screen", + sorting = Sorting.UNSORTED, preferences = setOf( SwitchPreference("revanced_hide_home_button"), SwitchPreference("revanced_hide_shorts_button"), - SwitchPreference("revanced_hide_subscriptions_button"), SwitchPreference("revanced_hide_create_button"), + SwitchPreference("revanced_hide_subscriptions_button"), SwitchPreference("revanced_switch_create_with_notifications_button"), ), - ) + ), ) /* @@ -82,14 +84,14 @@ object NavigationButtonsPatch : BytecodePatch( if (!it.resolve( context, initializeButtonsResult.mutableMethod, - initializeButtonsResult.mutableClass + initializeButtonsResult.mutableClass, ) - ) + ) { throw it.exception + } } .map { it.result!!.scanResult.patternScanResult!! } - val enumScanResult = fingerprintResults[0] val buttonViewResult = fingerprintResults[1] @@ -101,14 +103,14 @@ object NavigationButtonsPatch : BytecodePatch( */ val enumHook = "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->lastNavigationButton:Ljava/lang/Enum;" + "$INTEGRATIONS_CLASS_DESCRIPTOR->lastNavigationButton:Ljava/lang/Enum;" val buttonHook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->hideButton(Landroid/view/View;)V" + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideButton(Landroid/view/View;)V" // Inject bottom to top to not mess up the indices mapOf( buttonHook to buttonHookInsertIndex, - enumHook to enumHookInsertIndex + enumHook to enumHookInsertIndex, ).forEach { (hook, insertIndex) -> initializeButtonsResult.mutableMethod.injectHook(hook, insertIndex) } @@ -131,7 +133,7 @@ object NavigationButtonsPatch : BytecodePatch( """ invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->switchCreateWithNotificationButton()Z move-result v$conditionRegister - """ + """, ) } } ?: throw AddCreateButtonViewFingerprint.exception @@ -141,8 +143,9 @@ object NavigationButtonsPatch : BytecodePatch( */ InitializeButtonsFingerprint.result!!.let { - if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass)) + if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass)) { throw PivotBarCreateButtonViewFingerprint.exception + } } PivotBarCreateButtonViewFingerprint.result!!.apply { @@ -152,9 +155,9 @@ object NavigationButtonsPatch : BytecodePatch( * Inject hooks */ val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V" + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V" mutableMethod.injectHook(hook, insertIndex) } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt index bf52cb06..7d16a8e3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt @@ -52,7 +52,9 @@ object HidePlayerButtonsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_player_buttons")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_player_buttons") + ) PlayerControlsVisibilityModelFingerprint.result?.apply { val callIndex = scanResult.patternScanResult!!.endIndex diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsResourcePatch.kt index e05b3e8b..08b54204 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsResourcePatch.kt @@ -21,7 +21,9 @@ internal object AlbumCardsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_album_cards")) + SettingsPatch.PreferenceScreen.FEED.addPreferences( + SwitchPreference("revanced_hide_album_cards") + ) albumCardId = ResourceMappingPatch.resourceMappings.single { it.type == "layout" && it.name == "album_card" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsResourcePatch.kt index 31fb0b4a..81b69fe4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsResourcePatch.kt @@ -21,7 +21,9 @@ internal object BreakingNewsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_breaking_news")) + SettingsPatch.PreferenceScreen.FEED.addPreferences( + SwitchPreference("revanced_hide_breaking_news") + ) horizontalCardListId = ResourceMappingPatch.resourceMappings.single { it.type == "layout" && it.name == "horizontal_card_list" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt index ee2a9411..cfff7f9e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/CommentsPatch.kt @@ -47,9 +47,9 @@ object CommentsPatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( PreferenceScreen( - "revanced_comments_preference_screen", + "revanced_comments_screen", preferences = setOf( SwitchPreference("revanced_hide_comments_section"), SwitchPreference("revanced_hide_preview_comment") diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxResourcePatch.kt index 0ce74f7f..4e61c095 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxResourcePatch.kt @@ -21,7 +21,9 @@ internal object CrowdfundingBoxResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_crowdfunding_box")) + SettingsPatch.PreferenceScreen.FEED.addPreferences( + SwitchPreference("revanced_hide_crowdfunding_box") + ) crowdfundingBoxId = ResourceMappingPatch.resourceMappings.single { it.type == "layout" && it.name == "donation_companion" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsResourcePatch.kt index 6f601391..13231b7b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsResourcePatch.kt @@ -23,7 +23,9 @@ internal object HideEndscreenCardsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_endscreen_cards")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_endscreen_cards") + ) fun findEndscreenResourceId(name: String) = ResourceMappingPatch.resourceMappings.single { it.type == "layout" && it.name == "endscreen_element_layout_$name" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarResourcePatch.kt index 70ef188f..a10d22a0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarResourcePatch.kt @@ -18,9 +18,9 @@ internal object HideFilterBarResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.FEED.addPreferences( PreferenceScreen( - key = "revanced_hide_filter_bar_preference", + key = "revanced_hide_filter_bar_screen", preferences = setOf( SwitchPreference("revanced_hide_filter_bar_feed_in_feed"), SwitchPreference("revanced_hide_filter_bar_feed_in_search"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonResourcePatch.kt index 92f8f423..7dbd6a15 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonResourcePatch.kt @@ -22,7 +22,9 @@ internal object HideFloatingMicrophoneButtonResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_floating_microphone_button")) + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_hide_floating_microphone_button") + ) fabButtonId = ResourceMappingPatch.resourceMappings.find { it.type == "id" && it.name == "fab" }?.id ?: throw PatchException("Can not find required fab button resource id") diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt index 0825d786..caf22e8a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/fullscreenambientmode/DisableFullscreenAmbientModePatch.kt @@ -45,7 +45,7 @@ object DisableFullscreenAmbientModePatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( SwitchPreference("revanced_disable_fullscreen_ambient_mode") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt index de05d885..f72d80a3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/general/HideLayoutComponentsPatch.kt @@ -12,6 +12,8 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.InputType +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint @@ -19,7 +21,6 @@ import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverl import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.patches.youtube.misc.settings.SettingsPatch.PreferenceScreen import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -31,11 +32,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction dependencies = [ LithoFilterPatch::class, SettingsPatch::class, - AddResourcesPatch::class + AddResourcesPatch::class, ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", [ + "com.google.android.youtube", + [ "18.32.39", "18.37.36", "18.38.44", @@ -48,14 +50,14 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) - ] + "19.04.37", + ], + ), + ], ) @Suppress("unused") object HideLayoutComponentsPatch : BytecodePatch( - setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint) + setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint), ) { private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;" @@ -64,59 +66,68 @@ object HideLayoutComponentsPatch : BytecodePatch( private const val CUSTOM_FILTER_CLASS_NAME = "Lapp/revanced/integrations/youtube/patches/components/CustomFilter;" - override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference("revanced_hide_gray_separator"), - SwitchPreference("revanced_hide_join_membership_button"), - SwitchPreference("revanced_hide_channel_watermark"), - SwitchPreference("revanced_hide_for_you_shelf"), - SwitchPreference("revanced_hide_notify_me_button"), - SwitchPreference("revanced_hide_timed_reactions"), - SwitchPreference("revanced_hide_search_result_recommendations"), - SwitchPreference("revanced_hide_search_result_shelf_header"), - SwitchPreference("revanced_hide_channel_guidelines"), - SwitchPreference("revanced_hide_expandable_chip"), - SwitchPreference("revanced_hide_video_quality_menu_footer"), - SwitchPreference("revanced_hide_chapters"), - SwitchPreference("revanced_hide_community_posts"), - SwitchPreference("revanced_hide_compact_banner"), - SwitchPreference("revanced_hide_movies_section"), - SwitchPreference("revanced_hide_feed_survey"), - SwitchPreference("revanced_hide_community_guidelines"), - SwitchPreference("revanced_hide_subscribers_community_guidelines"), - SwitchPreference("revanced_hide_channel_member_shelf"), - SwitchPreference("revanced_hide_emergency_box"), - SwitchPreference("revanced_hide_info_panels"), - SwitchPreference("revanced_hide_medical_panels"), + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( SwitchPreference("revanced_hide_channel_bar"), - SwitchPreference("revanced_hide_quick_actions"), - SwitchPreference("revanced_hide_related_videos"), - SwitchPreference("revanced_hide_image_shelf"), - SwitchPreference("revanced_hide_latest_posts_ads"), - SwitchPreference("revanced_hide_mix_playlists"), - SwitchPreference("revanced_hide_artist_cards"), + SwitchPreference("revanced_hide_channel_guidelines"), + SwitchPreference("revanced_hide_channel_member_shelf"), + SwitchPreference("revanced_hide_channel_watermark"), SwitchPreference("revanced_hide_chips_shelf"), - app.revanced.patches.shared.misc.settings.preference.PreferenceScreen( - "revanced_hide_description_components_preference_screen", + SwitchPreference("revanced_hide_community_guidelines"), + PreferenceScreen( + key = "revanced_hide_description_components_screen", preferences = setOf( + SwitchPreference("revanced_hide_chapters"), SwitchPreference("revanced_hide_info_cards_section"), SwitchPreference("revanced_hide_game_section"), SwitchPreference("revanced_hide_music_section"), SwitchPreference("revanced_hide_podcast_section"), SwitchPreference("revanced_hide_transcript_section"), - ) + ), ), - app.revanced.patches.shared.misc.settings.preference.PreferenceScreen( - "revanced_custom_filter_preference_screen", + SwitchPreference("revanced_hide_emergency_box"), + SwitchPreference("revanced_hide_expandable_chip"), + SwitchPreference("revanced_hide_info_panels"), + SwitchPreference("revanced_hide_medical_panels"), + SwitchPreference("revanced_hide_quick_actions"), + SwitchPreference("revanced_hide_related_videos"), + SwitchPreference("revanced_hide_subscribers_community_guidelines"), + SwitchPreference("revanced_hide_timed_reactions"), + ) + + SettingsPatch.PreferenceScreen.FEED.addPreferences( + SwitchPreference("revanced_hide_artist_cards"), + SwitchPreference("revanced_hide_community_posts"), + SwitchPreference("revanced_hide_compact_banner"), + SwitchPreference("revanced_hide_feed_survey"), + SwitchPreference("revanced_hide_for_you_shelf"), + SwitchPreference("revanced_hide_image_shelf"), + SwitchPreference("revanced_hide_join_membership_button"), + SwitchPreference("revanced_hide_latest_posts_ads"), + SwitchPreference("revanced_hide_mix_playlists"), + SwitchPreference("revanced_hide_movies_section"), + SwitchPreference("revanced_hide_notify_me_button"), + SwitchPreference("revanced_hide_search_result_recommendations"), + SwitchPreference("revanced_hide_search_result_shelf_header"), + ) + + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_hide_gray_separator"), + PreferenceScreen( + key = "revanced_custom_filter_screen", + sorting = Sorting.UNSORTED, preferences = setOf( SwitchPreference("revanced_custom_filter"), // TODO: This should be a dynamic ListPreference, which does not exist yet - TextPreference("revanced_custom_filter_strings", inputType = InputType.TEXT_MULTI_LINE) - ) - ) + TextPreference("revanced_custom_filter_strings", inputType = InputType.TEXT_MULTI_LINE), + ), + ), + ) + + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( + SwitchPreference("revanced_hide_video_quality_menu_footer"), ) LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR) @@ -136,14 +147,15 @@ object HideLayoutComponentsPatch : BytecodePatch( val byteBufferRegister = getInstruction(consumeByteBufferIndex).registerD addInstructionsWithLabels( - consumeByteBufferIndex, """ + consumeByteBufferIndex, + """ invoke-static {v$conversionContextRegister, v$byteBufferRegister}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z move-result v0 # Conveniently same register happens to be free. if-nez v0, :return_empty_component - """, ExternalLabel("return_empty_component", returnEmptyComponentInstruction) + """, + ExternalLabel("return_empty_component", returnEmptyComponentInstruction), ) } - } ?: throw ParseElementFromBufferFingerprint.exception // endregion @@ -157,10 +169,11 @@ object HideLayoutComponentsPatch : BytecodePatch( removeInstruction(index) addInstructions( - index, """ + index, + """ invoke-static {}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->showWatermark()Z move-result p2 - """ + """, ) } ?: throw ShowWatermarkFingerprint.exception diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfocardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfocardsResourcePatch.kt index cde96076..6ac2377f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfocardsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfocardsResourcePatch.kt @@ -21,7 +21,9 @@ object HideInfocardsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_info_cards")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_info_cards") + ) drawerResourceId = ResourceMappingPatch.resourceMappings.single { it.type == "id" && it.name == "info_cards_drawer_header" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonResourcePatch.kt index 4ab73f3a..86d4734f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonResourcePatch.kt @@ -21,7 +21,9 @@ internal object HideLoadMoreButtonResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_load_more_button")) + SettingsPatch.PreferenceScreen.FEED.addPreferences( + SwitchPreference("revanced_hide_load_more_button") + ) expandButtonDownId = ResourceMappingPatch.resourceMappings.single { it.type == "layout" && it.name == "expand_button_down" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressPatch.kt deleted file mode 100644 index e69de29b..00000000 diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt index 1185ba7f..bdc042ab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch.kt @@ -50,7 +50,7 @@ object HidePlayerFlyoutMenuPatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( PreferenceScreen( key = KEY, preferences = setOf( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt index 70fde81b..1e1c1d93 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/rollingnumber/DisableRollingNumberAnimationPatch.kt @@ -49,7 +49,7 @@ object DisableRollingNumberAnimationPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( SwitchPreference("revanced_disable_rolling_number_animations") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt index 263b7bad..588367fd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/HideSeekbarPatch.kt @@ -8,7 +8,6 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.seekbar.SeekbarColorBytecodePatch -import app.revanced.patches.youtube.layout.seekbar.SeekbarPreferencesPatch import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.shared.fingerprints.SeekbarFingerprint @@ -21,7 +20,6 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint IntegrationsPatch::class, SettingsPatch::class, SeekbarColorBytecodePatch::class, - SeekbarPreferencesPatch::class, AddResourcesPatch::class ], compatiblePackages = [ @@ -51,7 +49,7 @@ object HideSeekbarPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SeekbarPreferencesPatch.addPreferences( + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( SwitchPreference("revanced_hide_seekbar"), SwitchPreference("revanced_hide_seekbar_thumbnail") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt index b9f411fe..83528f34 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsResourcePatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -17,24 +16,19 @@ object HideShortsComponentsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - PreferenceScreen( - "revanced_shorts_preference_screen", - preferences = setOf( - SwitchPreference("revanced_hide_shorts"), - SwitchPreference("revanced_hide_shorts_join_button"), - SwitchPreference("revanced_hide_shorts_subscribe_button"), - SwitchPreference("revanced_hide_shorts_subscribe_button_paused"), - SwitchPreference("revanced_hide_shorts_thanks_button"), - SwitchPreference("revanced_hide_shorts_comments_button"), - SwitchPreference("revanced_hide_shorts_remix_button"), - SwitchPreference("revanced_hide_shorts_share_button"), - SwitchPreference("revanced_hide_shorts_info_panel"), - SwitchPreference("revanced_hide_shorts_channel_bar"), - SwitchPreference("revanced_hide_shorts_sound_button"), - SwitchPreference("revanced_hide_shorts_navigation_bar") - ) - ) + SettingsPatch.PreferenceScreen.SHORTS.addPreferences( + SwitchPreference("revanced_hide_shorts"), + SwitchPreference("revanced_hide_shorts_join_button"), + SwitchPreference("revanced_hide_shorts_subscribe_button"), + SwitchPreference("revanced_hide_shorts_subscribe_button_paused"), + SwitchPreference("revanced_hide_shorts_thanks_button"), + SwitchPreference("revanced_hide_shorts_comments_button"), + SwitchPreference("revanced_hide_shorts_remix_button"), + SwitchPreference("revanced_hide_shorts_share_button"), + SwitchPreference("revanced_hide_shorts_info_panel"), + SwitchPreference("revanced_hide_shorts_channel_bar"), + SwitchPreference("revanced_hide_shorts_sound_button"), + SwitchPreference("revanced_hide_shorts_navigation_bar") ) ResourceMappingPatch.resourceMappings.find { diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenResourcePatch.kt index b190b321..28122d1a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenResourcePatch.kt @@ -21,7 +21,7 @@ internal object DisableSuggestedVideoEndScreenResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( SwitchPreference("revanced_disable_suggested_video_end_screen") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt index 673816e3..17d96a2f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/HideTimestampPatch.kt @@ -42,7 +42,9 @@ object HideTimestampPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_timestamp")) + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( + SwitchPreference("revanced_hide_timestamp") + ) TimeCounterFingerprint.result?.apply { mutableMethod.addInstructionsWithLabels( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt index eaf67270..47760116 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/PlayerPopupPanelsPatch.kt @@ -43,7 +43,9 @@ object PlayerPopupPanelsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_player_popup_panels")) + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_hide_player_popup_panels") + ) val engagementPanelControllerMethod = EngagementPanelControllerFingerprint .result?.mutableMethod ?: throw EngagementPanelControllerFingerprint.exception diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityResourcePatch.kt index a409030c..147ccacc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityResourcePatch.kt @@ -18,7 +18,7 @@ internal object CustomPlayerOverlayOpacityResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.PLAYER.addPreferences( TextPreference("revanced_player_overlay_opacity", inputType = InputType.NUMBER) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikeResourcePatch.kt index 848b86af..06226fc0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikeResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikeResourcePatch.kt @@ -7,6 +7,7 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.patches.youtube.misc.settings.SettingsResourcePatch @Patch( dependencies = [ @@ -20,15 +21,13 @@ internal object ReturnYouTubeDislikeResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - IntentPreference( - "revanced_ryd_settings", - intent = SettingsPatch.newIntent("revanced_ryd_settings_intent") - ) + SettingsResourcePatch += IntentPreference( + key = "revanced_settings_screen_09", + titleKey = "revanced_ryd_settings_title", + summaryKey = null, + intent = SettingsPatch.newIntent("revanced_ryd_settings_intent") ) - AddResourcesPatch(this::class) - oldUIDislikeId = ResourceMappingPatch.resourceMappings.single { it.type == "id" && it.name == "dislike_button" }.id diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt index 5fe87e4f..f981f8a5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt @@ -54,7 +54,9 @@ object WideSearchbarPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_wide_searchbar")) + SettingsPatch.PreferenceScreen.FEED.addPreferences( + SwitchPreference("revanced_wide_searchbar") + ) val result = CreateSearchSuggestionsFingerprint.result ?: throw CreateSearchSuggestionsFingerprint.exception diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt index 665190fd..a300571e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt @@ -10,12 +10,13 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.seekbar.fingerprints.FullscreenSeekbarThumbnailsFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.util.exception @Patch( name = "Restore old seekbar thumbnails", description = "Adds an option to restore the old seekbar thumbnails that appear above the seekbar while seeking instead of fullscreen thumbnails.", - dependencies = [IntegrationsPatch::class, SeekbarPreferencesPatch::class, AddResourcesPatch::class], + dependencies = [IntegrationsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -45,7 +46,9 @@ object RestoreOldSeekbarThumbnailsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SeekbarPreferencesPatch.addPreferences(SwitchPreference("revanced_restore_old_seekbar_thumbnails")) + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( + SwitchPreference("revanced_restore_old_seekbar_thumbnails") + ) FullscreenSeekbarThumbnailsFingerprint.result?.mutableMethod?.apply { val moveResultIndex = getInstructions().lastIndex - 1 diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarPreferencesPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarPreferencesPatch.kt deleted file mode 100644 index 0a9f7e27..00000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarPreferencesPatch.kt +++ /dev/null @@ -1,34 +0,0 @@ -package app.revanced.patches.youtube.layout.seekbar - -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.all.misc.resources.AddResourcesPatch -import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch -import app.revanced.patches.shared.misc.settings.preference.BasePreference -import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen -import app.revanced.patches.youtube.misc.settings.SettingsPatch -import java.io.Closeable - -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class]) -internal object SeekbarPreferencesPatch : ResourcePatch(), Closeable { - private val seekbarPreferences = mutableSetOf() - - override fun execute(context: ResourceContext) { - // Nothing to do here. All work is done in close method. - } - - override fun close() { - AddResourcesPatch(this::class) - - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - PreferenceScreen( - "revanced_seekbar_preference_screen", - preferences = seekbarPreferences, - ) - ) - } - - internal fun addPreferences(vararg preferencesToAdd: BasePreference) = - seekbarPreferences.addAll(preferencesToAdd) -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt index 335126a8..6484216c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockResourcePatch.kt @@ -8,6 +8,7 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.patches.youtube.misc.settings.SettingsResourcePatch import app.revanced.util.ResourceGroup import app.revanced.util.copyResources import app.revanced.util.copyXmlNode @@ -24,12 +25,13 @@ internal object SponsorBlockResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - IntentPreference( - "revanced_sb_settings", - intent = SettingsPatch.newIntent("revanced_sb_settings_intent"), - ), + SettingsResourcePatch += IntentPreference( + key = "revanced_settings_screen_10", + titleKey = "revanced_sb_settings_title", + summaryKey = null, + intent = SettingsPatch.newIntent("revanced_sb_settings_intent") ) + arrayOf( ResourceGroup( "layout", diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt index 8ac79711..eea41751 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt @@ -49,7 +49,7 @@ object SpoofAppVersionPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( SwitchPreference("revanced_spoof_app_version"), ListPreference( key = "revanced_spoof_app_version_target", diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt index 9016385a..e4f42397 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startpage/ChangeStartPagePatch.kt @@ -33,7 +33,7 @@ object ChangeStartPagePatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( ListPreference( key = "revanced_start_page", summaryKey = null, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt index 1cf63fc0..425adf11 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt @@ -56,7 +56,7 @@ object DisableResumingShortsOnStartupPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SettingsPatch.PreferenceScreen.SHORTS.addPreferences( SwitchPreference("revanced_disable_resuming_shorts_player") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt index 10dadae3..f09c7d69 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tablet/EnableTabletLayoutPatch.kt @@ -28,7 +28,9 @@ object EnableTabletLayoutPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_tablet_layout")) + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_tablet_layout") + ) GetFormFactorFingerprint.result?.let { it.mutableMethod.apply { diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt index e50e1a24..454cced2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/TabletMiniPlayerPatch.kt @@ -55,7 +55,9 @@ object TabletMiniPlayerPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_tablet_miniplayer")) + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_tablet_miniplayer") + ) // First resolve the fingerprints via the parent fingerprint. MiniPlayerDimensionsCalculatorParentFingerprint.result @@ -127,7 +129,7 @@ object TabletMiniPlayerPatch : BytecodePatch( ) } - fun MethodFingerprint.unwrap(): Triple { + private fun MethodFingerprint.unwrap(): Triple { val result = this.result!! val scanIndex = result.scanResult.patternScanResult!!.endIndex val method = result.mutableMethod diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt index be9aaaea..3ac26ac9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeBytecodePatch.kt @@ -100,7 +100,9 @@ object ThemeBytecodePatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_gradient_loading_screen")) + SettingsPatch.PreferenceScreen.GENERAL_LAYOUT.addPreferences( + SwitchPreference("revanced_gradient_loading_screen") + ) UseGradientLoadingScreenFingerprint.result?.mutableMethod?.apply { val isEnabledIndex = indexOfFirstWideLiteralInstructionValue(GRADIENT_LOADING_SCREEN_AB_CONSTANT) + 3 diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt index 2d5fef1e..80cff8a7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/ThemeResourcePatch.kt @@ -9,7 +9,6 @@ import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.TextPreference -import app.revanced.patches.youtube.layout.seekbar.SeekbarPreferencesPatch import app.revanced.patches.youtube.layout.theme.ThemeBytecodePatch.darkThemeBackgroundColor import app.revanced.patches.youtube.layout.theme.ThemeBytecodePatch.lightThemeBackgroundColor import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -19,7 +18,6 @@ import org.w3c.dom.Element dependencies = [ SettingsPatch::class, ResourceMappingPatch::class, - SeekbarPreferencesPatch::class, AddResourcesPatch::class, ], ) @@ -29,7 +27,7 @@ internal object ThemeResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { AddResourcesPatch(this::class) - SeekbarPreferencesPatch.addPreferences( + SettingsPatch.PreferenceScreen.SEEKBAR.addPreferences( SwitchPreference("revanced_seekbar_custom_color"), TextPreference("revanced_seekbar_custom_color_value", inputType = InputType.TEXT_CAP_CHARACTERS), ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt index 2bda4802..4c642c7b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsPatch.kt @@ -11,7 +11,10 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.all.misc.resources.AddResourcesPatch -import app.revanced.patches.shared.misc.settings.preference.* +import app.revanced.patches.shared.misc.settings.preference.ListPreference +import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.layout.thumbnails.fingerprints.MessageDigestImageUrlFingerprint import app.revanced.patches.youtube.layout.thumbnails.fingerprints.MessageDigestImageUrlParentFingerprint import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.RequestFingerprint @@ -34,8 +37,7 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod dependencies = [ IntegrationsPatch::class, SettingsPatch::class, - AlternativeThumbnailsResourcePatch::class, - AddResourcesPatch::class + AddResourcesPatch::class, ], compatiblePackages = [ CompatiblePackage( @@ -53,10 +55,10 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod "19.02.39", "19.03.35", "19.03.36", - "19.04.37" - ] - ) - ] + "19.04.37", + ], + ), + ], ) @Suppress("unused") object AlternativeThumbnailsPatch : BytecodePatch( @@ -64,7 +66,7 @@ object AlternativeThumbnailsPatch : BytecodePatch( MessageDigestImageUrlParentFingerprint, OnResponseStartedFingerprint, RequestFingerprint, - ) + ), ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch;" @@ -88,7 +90,7 @@ object AlternativeThumbnailsPatch : BytecodePatch( """ invoke-static { p1 }, $targetMethodClass->overrideImageURL(Ljava/lang/String;)Ljava/lang/String; move-result-object p1 - """ + """, ) loadImageUrlIndex += 2 } @@ -102,7 +104,7 @@ object AlternativeThumbnailsPatch : BytecodePatch( loadImageSuccessCallbackMethod.addInstruction( loadImageSuccessCallbackIndex++, "invoke-static { p1, p2 }, $targetMethodClass->handleCronetSuccess(" + - "Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;)V" + "Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;)V", ) } @@ -114,44 +116,32 @@ object AlternativeThumbnailsPatch : BytecodePatch( loadImageErrorCallbackMethod.addInstruction( loadImageErrorCallbackIndex++, "invoke-static { p1, p2, p3 }, $targetMethodClass->handleCronetFailure(" + - "Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;Ljava/io/IOException;)V" + "Lorg/chromium/net/UrlRequest;Lorg/chromium/net/UrlResponseInfo;Ljava/io/IOException;)V", ) } override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - PreferenceScreen( - "revanced_alt_thumbnail_preference_screen", - preferences = setOf( - NonInteractivePreference( - "revanced_alt_thumbnail_about", - null, // Summary is dynamically updated based on the current settings. - tag = "app.revanced.integrations.youtube.settings.preference.AlternativeThumbnailsStatusPreference" - ), - SwitchPreference("revanced_alt_thumbnail_dearrow"), - SwitchPreference("revanced_alt_thumbnail_dearrow_connection_toast"), - TextPreference("revanced_alt_thumbnail_dearrow_api_url"), - NonInteractivePreference( - "revanced_alt_thumbnail_dearrow_about", - // Custom about preference with link to the DeArrow website. - tag = "app.revanced.integrations.youtube.settings.preference.AlternativeThumbnailsAboutDeArrowPreference", - selectable = true - ), - SwitchPreference("revanced_alt_thumbnail_stills"), - ListPreference( - "revanced_alt_thumbnail_stills_time", - summaryKey = null, - ), - SwitchPreference("revanced_alt_thumbnail_stills_fast"), - NonInteractivePreference( - "revanced_alt_thumbnail_stills_about", - // Restore the preference dividers to keep it from looking weird. - selectable = true - ) - ) - ) + SettingsPatch.PreferenceScreen.ALTERNATIVE_THUMBNAILS.addPreferences( + NonInteractivePreference( + "revanced_alt_thumbnail_about", + null, // Summary is dynamically updated based on the current settings. + tag = "app.revanced.integrations.youtube.settings.preference.AlternativeThumbnailsStatusPreference", + ), + SwitchPreference("revanced_alt_thumbnail_dearrow"), + SwitchPreference("revanced_alt_thumbnail_dearrow_connection_toast"), + TextPreference("revanced_alt_thumbnail_dearrow_api_url"), + NonInteractivePreference( + "revanced_alt_thumbnail_dearrow_about", + // Custom about preference with link to the DeArrow website. + tag = "app.revanced.integrations.youtube.settings.preference.AlternativeThumbnailsAboutDeArrowPreference", + selectable = true, + ), + SwitchPreference("revanced_alt_thumbnail_stills"), + ListPreference("revanced_alt_thumbnail_stills_time", summaryKey = null), + SwitchPreference("revanced_alt_thumbnail_stills_fast"), + NonInteractivePreference("revanced_alt_thumbnail_stills_about"), ) fun MethodFingerprint.getResultOrThrow() = @@ -162,7 +152,7 @@ object AlternativeThumbnailsPatch : BytecodePatch( fun MethodFingerprint.resolveAndLetMutableMethod( fingerprint: MethodFingerprint, - block: (MutableMethod) -> Unit + block: (MutableMethod) -> Unit, ) = alsoResolve(fingerprint).also { block(it.mutableMethod) } MessageDigestImageUrlFingerprint.resolveAndLetMutableMethod(MessageDigestImageUrlParentFingerprint) { @@ -203,15 +193,16 @@ object AlternativeThumbnailsPatch : BytecodePatch( AccessFlags.PUBLIC.value, null, null, - MutableMethodImplementation(2) + MutableMethodImplementation(2), ).toMutable().apply { addInstructions( """ - iget-object v0, p0, $definingClass->${urlFieldName}:Ljava/lang/String; + iget-object v0, p0, $definingClass->$urlFieldName:Ljava/lang/String; return-object v0 - """ + """, ) - }) + }, + ) } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsResourcePatch.kt deleted file mode 100644 index d926b4a4..00000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsResourcePatch.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.youtube.layout.thumbnails - -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.all.misc.resources.AddResourcesPatch -import app.revanced.patches.youtube.misc.settings.SettingsPatch - -@Patch( - dependencies = [ - SettingsPatch::class, - AddResourcesPatch::class - ] -) -internal object AlternativeThumbnailsResourcePatch : ResourcePatch() { - override fun execute(context: ResourceContext) { - AddResourcesPatch(this::class) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt index 66b01d8e..f7b43a2b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/announcements/AnnouncementsPatch.kt @@ -29,7 +29,9 @@ object AnnouncementsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_announcements")) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_announcements") + ) val onCreateMethod = MainActivityFingerprint.result?.let { it.mutableClass.methods.find { method -> method.name == "onCreate" } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt index 5f3eb7ae..f30ce323 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/AutoRepeatPatch.kt @@ -47,7 +47,9 @@ object AutoRepeatPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_auto_repeat")) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_auto_repeat") + ) //Get Result from the ParentFingerprint which is the playMethod we need to get. val parentResult = AutoRepeatParentFingerprint.result diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/DebuggingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/DebuggingPatch.kt index 01576ee2..523a76d5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/DebuggingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/DebuggingPatch.kt @@ -6,6 +6,7 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -14,7 +15,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch name = "Enable debugging", description = "Adds options for debugging.", dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], - compatiblePackages = [CompatiblePackage("com.google.android.youtube")] + compatiblePackages = [CompatiblePackage("com.google.android.youtube")], ) @Suppress("unused") object DebuggingPatch : ResourcePatch() { @@ -23,14 +24,15 @@ object DebuggingPatch : ResourcePatch() { SettingsPatch.PreferenceScreen.MISC.addPreferences( PreferenceScreen( - "revanced_debug_preference_screen", + key = "revanced_debug_screen", + sorting = Sorting.UNSORTED, preferences = setOf( SwitchPreference("revanced_debug"), SwitchPreference("revanced_debug_protobuffer"), SwitchPreference("revanced_debug_stacktrace"), - SwitchPreference("revanced_debug_toast_on_error") - ) - ) + SwitchPreference("revanced_debug_toast_on_error"), + ), + ), ) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt index 21819947..5e871159 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/dimensions/spoof/SpoofDeviceDimensionsPatch.kt @@ -45,7 +45,9 @@ object SpoofDeviceDimensionsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_spoof_device_dimensions",)) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_spoof_device_dimensions") + ) DeviceDimensionsModelToStringFingerprint.result ?.mutableClass?.methods?.find { method -> method.name == "" } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt index 25c31d66..5a00c791 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt @@ -10,8 +10,19 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.fix.playback.fingerprints.* +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.ParamsMapPutFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerResponseModelImplGeneralFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerResponseModelImplLiveStreamFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerResponseModelImplRecommendedLevelFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.ScrubbedPreviewLayoutFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.StoryboardRendererDecoderRecommendedLevelFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.StoryboardRendererDecoderSpecFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.StoryboardRendererSpecFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.StoryboardThumbnailFingerprint +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.StoryboardThumbnailParentFingerprint import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.video.information.VideoInformationPatch @@ -54,7 +65,8 @@ object SpoofSignaturePatch : BytecodePatch( SettingsPatch.PreferenceScreen.MISC.addPreferences( PreferenceScreen( - "revanced_spoof_signature_verification", + key = "revanced_spoof_signature_verification_screen", + sorting = Sorting.UNSORTED, preferences = setOf( SwitchPreference("revanced_spoof_signature_verification_enabled"), SwitchPreference("revanced_spoof_signature_in_feed_enabled"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt index d5e7a5f7..b140c3b5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/BypassURLRedirectsPatch.kt @@ -44,7 +44,9 @@ object BypassURLRedirectsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_bypass_url_redirects" )) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_bypass_url_redirects") + ) mapOf( ABUriParserFingerprint to 7, // Offset to Uri.parse. diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt index 76c5764b..a76331da 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch.kt @@ -71,7 +71,9 @@ object OpenLinksExternallyPatch : BaseTransformInstructionsPatch> override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_external_browser")) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_external_browser") + ) super.execute(context) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/MinimizedPlaybackPatch.kt index f89938ed..e83b4b49 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/MinimizedPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/MinimizedPlaybackPatch.kt @@ -61,13 +61,7 @@ object MinimizedPlaybackPatch : BytecodePatch( AddResourcesPatch(this::class) SettingsPatch.PreferenceScreen.MISC.addPreferences( - NonInteractivePreference( - "revanced_minimized_playback_enabled", - "revanced_minimized_playback_summary_on", - // Use horizontal dividers to keep the settings from looking weird. - // If PreferenceCategories are added, then this should be removed. - selectable = true - ) + NonInteractivePreference("revanced_minimized_playback") ) MinimizedPlaybackManagerFingerprint.result?.apply { diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt index 0414cb7f..06c737fe 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt @@ -51,7 +51,9 @@ object RemoveTrackingQueryParameterPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_remove_tracking_query_parameter")) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_remove_tracking_query_parameter") + ) fun MethodFingerprint.hook( getInsertIndex: PatternScanResult.() -> Int, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt index dd33c863..0ada6925 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsPatch.kt @@ -9,10 +9,11 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen import app.revanced.patches.shared.misc.settings.preference.InputType import app.revanced.patches.shared.misc.settings.preference.IntentPreference +import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting import app.revanced.patches.shared.misc.settings.preference.TextPreference -import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.fingerprints.LicenseActivityOnCreateFingerprint import app.revanced.patches.youtube.misc.settings.fingerprints.SetThemeFingerprint @@ -27,12 +28,14 @@ import java.io.Closeable dependencies = [ IntegrationsPatch::class, SettingsResourcePatch::class, - AddResourcesPatch::class - ] + AddResourcesPatch::class, + ], ) -object SettingsPatch : BytecodePatch( - setOf(LicenseActivityOnCreateFingerprint, SetThemeFingerprint) -), Closeable { +object SettingsPatch : + BytecodePatch( + setOf(LicenseActivityOnCreateFingerprint, SetThemeFingerprint), + ), + Closeable { private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations/youtube" private const val ACTIVITY_HOOK_CLASS_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settings/LicenseActivityHook;" @@ -48,8 +51,8 @@ object SettingsPatch : BytecodePatch( titleKey = "revanced_pref_import_export_title", summaryKey = "revanced_pref_import_export_summary", inputType = InputType.TEXT_MULTI_LINE, - tag = "app.revanced.integrations.shared.settings.preference.ImportExportPreference" - ) + tag = "app.revanced.integrations.shared.settings.preference.ImportExportPreference", + ), ) SetThemeFingerprint.result?.mutableMethod?.let { setThemeMethod -> @@ -66,7 +69,7 @@ object SettingsPatch : BytecodePatch( replaceInstruction( returnIndex, "invoke-static { v$register }, " + - "$THEME_HELPER_DESCRIPTOR->$SET_THEME_METHOD_NAME(Ljava/lang/Object;)V" + "$THEME_HELPER_DESCRIPTOR->$SET_THEME_METHOD_NAME(Ljava/lang/Object;)V", ) addInstruction(returnIndex + 1, "return-object v$register") } @@ -82,7 +85,7 @@ object SettingsPatch : BytecodePatch( """ invoke-static { p0 }, $ACTIVITY_HOOK_CLASS_DESCRIPTOR->initialize(Landroid/app/Activity;)V return-void - """ + """, ) // Remove other methods as they will break as the onCreate method is modified above. @@ -97,18 +100,67 @@ object SettingsPatch : BytecodePatch( */ fun newIntent(settingsName: String) = IntentPreference.Intent( data = settingsName, - targetClass = "com.google.android.libraries.social.licenses.LicenseActivity" + targetClass = "com.google.android.libraries.social.licenses.LicenseActivity", ) { // The package name change has to be reflected in the intent. ChangePackageNamePatch.setOrGetFallbackPackageName("com.google.android.youtube") } object PreferenceScreen : BasePreferenceScreen() { - val ADS = Screen("revanced_ads_screen") - val INTERACTIONS = Screen("revanced_interactions_screen") - val LAYOUT = Screen("revanced_layout_screen") - val VIDEO = Screen("revanced_video_screen") - val MISC = Screen("revanced_misc_screen") + // Sort screens in the root menu by key, to not scatter related items apart + // (sorting key is set in revanced_prefs.xml). + // If no preferences are added to a screen, the screen will not be added to the settings. + val ADS = Screen( + key = "revanced_settings_screen_01_ads", + summaryKey = null, + ) + val ALTERNATIVE_THUMBNAILS = Screen( + key = "revanced_settings_screen_02_alt_thumbnails", + summaryKey = null, + sorting = Sorting.UNSORTED, + ) + val FEED = Screen( + key = "revanced_settings_screen_03_feed", + summaryKey = null, + ) + val PLAYER = Screen( + key = "revanced_settings_screen_04_player", + summaryKey = null, + ) + val GENERAL_LAYOUT = Screen( + key = "revanced_settings_screen_05_general", + summaryKey = null, + ) + // Don't sort, as related preferences are scattered apart. + // Can use title sorting after PreferenceCategory support is added. + val SHORTS = Screen( + key = "revanced_settings_screen_06_shorts", + summaryKey = null, + sorting = Sorting.UNSORTED, + ) + // Don't sort, because title sorting scatters the custom color preferences. + val SEEKBAR = Screen( + key = "revanced_settings_screen_07_seekbar", + summaryKey = null, + sorting = Sorting.UNSORTED, + ) + val SWIPE_CONTROLS = Screen( + key = "revanced_settings_screen_08_swipe_controls", + summaryKey = null, + sorting = Sorting.UNSORTED, + ) + + // RYD and SB are items 9 and 10. + // Menus are added in their own patch because they use an Intent and not a Screen. + + val MISC = Screen( + key = "revanced_settings_screen_11_misc", + summaryKey = null, + ) + val VIDEO = Screen( + key = "revanced_settings_screen_12_video", + summaryKey = null, + ) override fun commit(screen: app.revanced.patches.shared.misc.settings.preference.PreferenceScreen) { SettingsResourcePatch += screen diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt index 3fbbc87f..3f8b1d16 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/SettingsResourcePatch.kt @@ -1,6 +1,7 @@ package app.revanced.patches.youtube.misc.settings import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchException import app.revanced.patches.all.misc.resources.AddResourcesPatch import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.shared.misc.settings.BaseSettingsResourcePatch @@ -11,7 +12,8 @@ import org.w3c.dom.Element object SettingsResourcePatch : BaseSettingsResourcePatch( IntentPreference( - "revanced_settings", + titleKey = "revanced_settings_title", + summaryKey = null, intent = SettingsPatch.newIntent("revanced_settings_intent"), ) to "settings_fragment", dependencies = @@ -40,12 +42,29 @@ object SettingsResourcePatch : BaseSettingsResourcePatch( context.copyResources("settings", resourceGroup) } + // Remove horizontal divider from the settings Preferences + // To better match the appearance of the stock YouTube settings. + context.xmlEditor["res/values/styles.xml"].use { editor -> + val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + val name = node.getAttribute("name") + if (name == "Theme.YouTube.Settings" || name == "Theme.YouTube.Settings.Dark") { + val listDividerNode = editor.file.createElement("item") + listDividerNode.setAttribute("name", "android:listDivider") + listDividerNode.appendChild(editor.file.createTextNode("@null")) + node.appendChild(listDividerNode) + } + } + } + // Modify the manifest and add a data intent filter to the LicenseActivity. // Some devices freak out if undeclared data is passed to an intent, // and this change appears to fix the issue. + var modifiedIntent = false context.xmlEditor["AndroidManifest.xml"].use { editor -> val document = editor.file - // A xml regular-expression would probably work better than this manual searching. val manifestNodes = document.getElementsByTagName("manifest").item(0).childNodes for (i in 0..manifestNodes.length) { @@ -62,11 +81,14 @@ object SettingsResourcePatch : BaseSettingsResourcePatch( mimeType.setAttribute("android:mimeType", "text/plain") intentFilter.appendChild(mimeType) applicationChild.appendChild(intentFilter) + modifiedIntent = true break } } } } } + + if (!modifiedIntent) throw PatchException("Could not modify activity intent") } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt index aadee4ab..261005b3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/ZoomHapticsPatch.kt @@ -25,7 +25,9 @@ object ZoomHapticsPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_disable_zoom_haptics")) + SettingsPatch.PreferenceScreen.MISC.addPreferences( + SwitchPreference("revanced_disable_zoom_haptics") + ) val zoomHapticsFingerprintMethod = ZoomHapticsFingerprint.result!!.mutableMethod diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt index d8da8dc4..cb255b32 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/HDRBrightnessPatch.kt @@ -45,7 +45,9 @@ object HDRBrightnessPatch : BytecodePatch( override fun execute(context: BytecodeContext) { AddResourcesPatch(this::class) - SettingsPatch.PreferenceScreen.VIDEO.addPreferences(SwitchPreference("revanced_hdr_auto_brightness")) + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( + SwitchPreference("revanced_hdr_auto_brightness") + ) val method = HDRBrightnessFingerprint.result!!.mutableMethod diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 390750d1..c7461f62 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -18,37 +18,29 @@ - - Showing original YouTube thumbnails - Showing still video captures - Showing DeArrow thumbnails. If a video has no DeArrow thumbnails then the original YouTube thumbnails are shown - Showing DeArrow thumbnails. If a video has no DeArrow thumbnails then still video captures are shown - DeArrow temporarily not available (status code: %s) - DeArrow temporarily not available - ReVanced - ReVanced specific settings Import / Export Import / Export ReVanced settings - Ads - Ad related settings - Interactions - Settings related to interactions - Layout - Settings related to the layout - Video - Settings related to the video player - Misc - Miscellaneous patches + Ads + Alternative thumbnails + Feed + Player + General layout + Shorts + Seekbar + Swipe controls + Misc + Video + Debugging + Enable or disable debugging options Debug logging Debug logs are enabled Debug logs are disabled - Debugging Log protocol buffer Debug logs include proto buffer Debug logs do not include proto buffer @@ -59,18 +51,15 @@ Toast shown if error occurs Toast not shown if error occurs Turning off error toasts hides all ReVanced error notifications.\n\nYou will not be notified of any unexpected events. - Enable or disable debugging options - Ads - Ad related settings Hide gray separator Gray separators are hidden Gray separators are shown Hide \'Join\' button Button is hidden Button is shown - Hide channel watermark in video player + Hide channel watermark Watermark is hidden Watermark is shown Hide \'For you\' shelf in channel page @@ -97,9 +86,6 @@ Hide video quality menu footer Video quality menu footer is hidden Video quality menu footer is shown - Hide chapters in the video description - Chapters are hidden - Chapters are shown Hide community posts Community posts are hidden Community posts are shown @@ -154,10 +140,12 @@ Hide chips shelf Chips shelf is hidden Chips shelf is shown - Hide components in the video description Hide info cards section Info cards section is hidden Info cards section is shown + Hide chapters + Chapters are hidden + Chapters are shown Hide game section Game section is hidden Game section is shown @@ -170,14 +158,15 @@ Hide transcript section Transcript section is hidden Transcript section is shown - Hide components under the video description - Custom filter + Video description + Hide or show video description components + Custom filter + Hide components using custom filters Enable custom filter Custom filter is enabled Custom filter is disabled Custom filter List of component path builder strings to filter separated by new line - Hide components using custom filters Invalid custom filter (must be ASCII only): %s Invalid custom filter: %s Custom filter reset to default @@ -224,14 +213,12 @@ URL copied to clipboard URL with timestamp copied - Copy video URL settings Show copy video URL button Button is shown. Tap to copy video URL. Tap and hold to copy video URL with timestamp Button is not shown Show copy timestamp URL button Button is shown. Tap to copy video URL with timestamp. Tap and hold to copy video without timestamp Button is not shown - Settings related to copy URL buttons in video player Remove viewer discretion dialog @@ -240,14 +227,14 @@ This does not bypass the age restriction. It just accepts it automatically. - %s is not installed. Please install it. - External download settings + External downloads + Settings for using an external downloader Show external download button Download button shown in player Download button not shown in player Downloader package name Package name of your installed external downloader app, such as NewPipe or Seal - Settings for using an external downloader + %s is not installed. Please install it. Disable precise seeking gesture @@ -260,7 +247,6 @@ Seekbar tapping is disabled - Swipe controls Enable brightness gesture Brightness swipe is enabled Brightness swipe is disabled @@ -284,7 +270,6 @@ The visibility of swipe overlay background Swipe magnitude threshold The amount of threshold for swipe to occur - Control volume and brightness Disable auto captions @@ -292,38 +277,35 @@ Auto captions are enabled - Hide action buttons - Hide like and dislike buttons - Like and dislike buttons are hidden - Like and dislike buttons are shown - Hide live chat button - Live chat button is hidden - Live chat button is shown - Hide share button + Action buttons + Hide or show buttons under videos + Hide Like and Dislike + Like and Dislike buttons are hidden + Like and Dislike buttons are shown + Hide Share Share button is hidden Share button is shown - Hide report button + Hide Report Report button is hidden Report button is shown - Hide remix button + Hide Remix Remix button is hidden Remix button is shown - Hide download button + Hide Download Download button is hidden Download button is shown - Hide thanks button + Hide Thanks Thanks button is hidden Thanks button is shown - Hide clip button + Hide Clip Clip button is hidden Clip button is shown - Hide save to playlist button - Save button is hidden - Save button is shown - Hide shop button + Hide Save to playlist + Save to playlist button is hidden + Save to playlist button is shown + Hide Shop Shop button is hidden Shop button is shown - Hide or show buttons under videos Hide autoplay button @@ -341,57 +323,57 @@ Cast button is shown - Navigation buttons - Hide home button + Navigation buttons + Hide or change buttons in the navigation bar + Hide Home Home button is hidden Home button is shown - Hide Shorts button + Hide Shorts Shorts button is hidden Shorts button is shown - Hide subscriptions button - Home subscriptions is hidden - Home subscriptions is shown - Hide create button + Hide Create Create button is hidden Create button is shown - Switch create with notifications button - Create button is switched with notifications - Create button is not switched with notifications - Hide or change buttons in the navigation bar + Hide Subscriptions + Subscriptions button is hidden + Subscriptions button is shown + Switch Create with Notifications + Create button is switched with Notifications button + Create button is not switched with Notifications button - Player flyout menu items - Manage the visibility of player flyout menu items - Hide Captions menu - Captions menu item is hidden - Captions menu item is shown - Hide Additional settings menu - Additional settings menu item is hidden - Additional settings menu item is shown - Hide Loop video menu - Loop video menu item is hidden - Loop video menu item is shown - Hide Ambient mode menu - Ambient mode menu item is hidden - Ambient mode menu item is shown - Hide Report menu - Report menu item is hidden - Report menu item is shown - Hide Help menu - Help menu item is hidden - Help menu item is shown - Hide Speed menu - Speed menu item is hidden - Speed menu item is shown - Hide More info menu - More info menu item is hidden - More info menu item is shown - Hide Audio track menu - Audio track menu item is hidden - Audio track menu item is shown - Hide Watch in VR menu - Watch in VR menu item is hidden - Watch in VR menu item is shown + Flyout menu + Hide or show player flyout menu items + Hide Captions + Captions menu is hidden + Captions menu is shown + Hide Additional settings + Additional settings menu is hidden + Additional settings menu is shown + Hide Loop video + Loop video menu is hidden + Loop video menu is shown + Hide Ambient mode + Ambient mode menu is hidden + Ambient mode menu is shown + Hide Report + Report menu is hidden + Report menu is shown + Hide Help & feedback + Help & feedback menu is hidden + Help & feedback menu is shown + Hide Playback speed + Playback speed menu is hidden + Playback speed menu is shown + Hide More info + More info menu is hidden + More info menu is shown + Hide Audio track + Audio track menu is hidden + Audio track menu is shown + Hide Watch in VR + Watch in VR menu is hidden + Watch in VR menu is shown Hide previous & next video buttons @@ -409,14 +391,14 @@ Breaking news are shown - Comments + Comments + Hide or show comments section components Hide comments section Comment section is hidden Comment section is shown Hide preview comment Preview comment is hidden Preview comment is shown - Manage the visibility of comments section components Hide crowdfunding box @@ -429,7 +411,8 @@ End screen cards are shown - Hide filter bar + Filter bar + Hide or show the filter bar in the feed, search, and related videos Hide in feed Hidden in feed Shown in feed @@ -439,7 +422,6 @@ Hide in related videos Hidden in related videos Shown in related videos - Manage the visibility of the filter bar in the feed, search and related videos Hide floating microphone button @@ -478,7 +460,6 @@ Thumbnail seekbar is shown - Shorts components Hide Shorts in feed Shorts are hidden Shorts are shown @@ -515,7 +496,6 @@ Hide navigation bar Navigation bar is hidden Navigation bar is shown - Manage the visibility of Shorts components Disable suggested video end screen @@ -538,7 +518,6 @@ Return YouTube Dislike - Settings for Return YouTube Dislike Hidden Dislikes temporarily not available (API timed out) Dislikes not available (status %d) @@ -594,13 +573,8 @@ Seekbar thumbnails will appear above the seekbar Seekbar thumbnails will appear in fullscreen - - Seekbar - Settings for the seekbar - SponsorBlock - SponsorBlock related settings Enable SponsorBlock SponsorBlock is a crowd-sourced system for skipping annoying parts of YouTube videos Appearance @@ -833,7 +807,6 @@ Invalid seekbar color value. Using default value. - Alternative thumbnails Thumbnails in use Enable DeArrow thumbnails Using DeArrow thumbnails @@ -857,7 +830,12 @@ Using high quality still captures About still video captures Still captures are taken from the beginning/middle/end of each video. These images are built into YouTube and no external API is used - Video thumbnail settings + Showing original YouTube thumbnails + Showing still video captures + Showing DeArrow thumbnails. If a video has no DeArrow thumbnails then the original YouTube thumbnails are shown + Showing DeArrow thumbnails. If a video has no DeArrow thumbnails then still video captures are shown + DeArrow temporarily not available (status code: %s) + DeArrow temporarily not available Show ReVanced announcements @@ -877,7 +855,8 @@ Device dimensions not spoofed\n\nSpoofing the device dimensions can unlock higher video qualities but unknown side effects may occur - Spoof app signature + Spoof app signature + Spoof the app signature to prevent playback issues Spoof app signature App signature spoofed\n\nSide effects include:\n• Enhanced bitrate is not available\n• Videos cannot be downloaded\n• No seekbar thumbnails for paid videos App signature not spoofed\n\nVideo playback may not work @@ -888,7 +867,6 @@ Spoof storyboard Storyboard spoofed Storyboard not spoofed\n\nSide effects include:\n• No ambient mode\n• Seekbar thumbnails are hidden - Spoof the app signature to prevent playback issues Spoof storyboard temporarily not available (API timed out) Spoof storyboard temporarily not available: %s @@ -907,8 +885,8 @@ Opening links in app - Minimized playback - This setting can be found in Settings -> Background + Minimized playback + This setting can be found in Settings -> Background Remove tracking query parameter @@ -1006,9 +984,6 @@ ReVanced Settings - Debug logging - Debug logs are enabled - Debug logs are disabled Ads Ad blocking settings Chat @@ -1019,6 +994,9 @@ Other settings Client-side ads Server-side surestream ads + Debug logging + Debug logs are enabled + Debug logs are disabled \ No newline at end of file diff --git a/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml b/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml index 15008811..c78967c6 100644 --- a/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml +++ b/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml @@ -13,7 +13,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/yt_white1" - android:elevation="4dp"> + android:elevation="0dp"> + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:yt="http://schemas.android.com/apk/res-auto" + android:key="revanced_settings_root_screen_sort_by_key"> \ No newline at end of file From 931a6f81d60925563b9a5515229e819635988ba9 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 2 Mar 2024 07:29:04 +0000 Subject: [PATCH 48/52] chore(release): 4.3.0-dev.13 [skip ci] # [4.3.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.12...v4.3.0-dev.13) (2024-03-02) ### Features * **YouTube:** Reorganize settings menu ([#2737](https://github.com/ReVanced/revanced-patches/issues/2737)) ([36132df](https://github.com/ReVanced/revanced-patches/commit/36132df4be6a04c08b6f3dd79de1bcea93a80fb8)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c64506ef..bd7caaf2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.3.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.12...v4.3.0-dev.13) (2024-03-02) + + +### Features + +* **YouTube:** Reorganize settings menu ([#2737](https://github.com/ReVanced/revanced-patches/issues/2737)) ([36132df](https://github.com/ReVanced/revanced-patches/commit/36132df4be6a04c08b6f3dd79de1bcea93a80fb8)) + # [4.3.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.11...v4.3.0-dev.12) (2024-03-02) diff --git a/gradle.properties b/gradle.properties index 82b7515e..40231653 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.12 +version = 4.3.0-dev.13 From ff316c1ac14f8c9b2ab0597bfd6dbe5afe3d8abc Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Sat, 2 Mar 2024 18:59:36 +0000 Subject: [PATCH 49/52] chore(release): 4.3.0 [skip ci] # [4.3.0](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0) (2024-03-02) ### Bug Fixes * Compile DEX without debugging information ([f5df957](https://github.com/ReVanced/revanced-patches/commit/f5df9578669f71a67411bc93a25a7e8da43610d0)) * **Override certificate pinning:** Always overwrite with a generic network security configuration ([2a842a1](https://github.com/ReVanced/revanced-patches/commit/2a842a1e14e1993eb028ae0bd1a93e227bb929a6)) * Remove extra space from patch description ([#2780](https://github.com/ReVanced/revanced-patches/issues/2780)) ([96a3f35](https://github.com/ReVanced/revanced-patches/commit/96a3f359266ff8d16ae9ee3c6ce2f16ce67a3b93)) * Use deprecated members to ensure backwards compatibility ([083bd40](https://github.com/ReVanced/revanced-patches/commit/083bd4009231b9612394b4496ca1d329947d6577)) * **YouTube - Spoof app version:** Remove broken versions ([#2776](https://github.com/ReVanced/revanced-patches/issues/2776)) ([9466d97](https://github.com/ReVanced/revanced-patches/commit/9466d973c6d7a2891e3fa9f283107b64399152ea)) * **YouTube - Spoof signature:** Fix tracking such as history or watch time ([bcd8b48](https://github.com/ReVanced/revanced-patches/commit/bcd8b48e70693dac1bfcc0bf4971d6b526065b59)) ### Features * **OpeningHours:** Add `Fix crash` patch ([#2697](https://github.com/ReVanced/revanced-patches/issues/2697)) ([0d011b8](https://github.com/ReVanced/revanced-patches/commit/0d011b876ecf05031a7daa54ab7e6d3506728a47)) * Remove unnecessary description from patch ([1a89dd9](https://github.com/ReVanced/revanced-patches/commit/1a89dd9f8cd0c614055a9da97338839b77a25ed1)) * **Sync for Reddit:** Add `Fix /s/ links` patch ([f15ef3f](https://github.com/ReVanced/revanced-patches/commit/f15ef3f63460254236185f8e22c9395db4db9465)) * **Twitter - Unlock downloads:** Unlock GIF downloads ([d0f91c8](https://github.com/ReVanced/revanced-patches/commit/d0f91c8550592723e1252e1af2971b508591dd59)) * **VSCO - Unlock pro:** Constrain to last working version ([6dd4a7c](https://github.com/ReVanced/revanced-patches/commit/6dd4a7c29e48c3bc517bbdd7ed160624c36c2333)) * **X:** Add `Open links as query` patch ([#2730](https://github.com/ReVanced/revanced-patches/issues/2730)) ([ba75a51](https://github.com/ReVanced/revanced-patches/commit/ba75a51b71dbb9157db230b3e97a90361019fe30)) * **YouTube - Change header:** Improve patch option description ([3b8bc08](https://github.com/ReVanced/revanced-patches/commit/3b8bc08d4ed3a3a0f96d2f476e5059840b9f9d9b)) * **YouTube - Change start page:** Add more start pages ([cc1d9b7](https://github.com/ReVanced/revanced-patches/commit/cc1d9b743633c619fb6acc428e884c1c9b53e10b)) * **YouTube - Custom branding:** Improve patch option description ([e27f56c](https://github.com/ReVanced/revanced-patches/commit/e27f56c8a34d41167b290f47280276c1c6003876)) * **YouTube - Spoof app version:** Add target versions ([#2787](https://github.com/ReVanced/revanced-patches/issues/2787)) ([83a7bd8](https://github.com/ReVanced/revanced-patches/commit/83a7bd8d69e62623fc4d2ba73d9fb49e92751d89)) * **YouTube:** Reorganize settings menu ([#2737](https://github.com/ReVanced/revanced-patches/issues/2737)) ([36132df](https://github.com/ReVanced/revanced-patches/commit/36132df4be6a04c08b6f3dd79de1bcea93a80fb8)) --- CHANGELOG.md | 27 +++++++++++++++++++++++++++ gradle.properties | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd7caaf2..fd23acdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +# [4.3.0](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0) (2024-03-02) + + +### Bug Fixes + +* Compile DEX without debugging information ([f5df957](https://github.com/ReVanced/revanced-patches/commit/f5df9578669f71a67411bc93a25a7e8da43610d0)) +* **Override certificate pinning:** Always overwrite with a generic network security configuration ([2a842a1](https://github.com/ReVanced/revanced-patches/commit/2a842a1e14e1993eb028ae0bd1a93e227bb929a6)) +* Remove extra space from patch description ([#2780](https://github.com/ReVanced/revanced-patches/issues/2780)) ([96a3f35](https://github.com/ReVanced/revanced-patches/commit/96a3f359266ff8d16ae9ee3c6ce2f16ce67a3b93)) +* Use deprecated members to ensure backwards compatibility ([083bd40](https://github.com/ReVanced/revanced-patches/commit/083bd4009231b9612394b4496ca1d329947d6577)) +* **YouTube - Spoof app version:** Remove broken versions ([#2776](https://github.com/ReVanced/revanced-patches/issues/2776)) ([9466d97](https://github.com/ReVanced/revanced-patches/commit/9466d973c6d7a2891e3fa9f283107b64399152ea)) +* **YouTube - Spoof signature:** Fix tracking such as history or watch time ([bcd8b48](https://github.com/ReVanced/revanced-patches/commit/bcd8b48e70693dac1bfcc0bf4971d6b526065b59)) + + +### Features + +* **OpeningHours:** Add `Fix crash` patch ([#2697](https://github.com/ReVanced/revanced-patches/issues/2697)) ([0d011b8](https://github.com/ReVanced/revanced-patches/commit/0d011b876ecf05031a7daa54ab7e6d3506728a47)) +* Remove unnecessary description from patch ([1a89dd9](https://github.com/ReVanced/revanced-patches/commit/1a89dd9f8cd0c614055a9da97338839b77a25ed1)) +* **Sync for Reddit:** Add `Fix /s/ links` patch ([f15ef3f](https://github.com/ReVanced/revanced-patches/commit/f15ef3f63460254236185f8e22c9395db4db9465)) +* **Twitter - Unlock downloads:** Unlock GIF downloads ([d0f91c8](https://github.com/ReVanced/revanced-patches/commit/d0f91c8550592723e1252e1af2971b508591dd59)) +* **VSCO - Unlock pro:** Constrain to last working version ([6dd4a7c](https://github.com/ReVanced/revanced-patches/commit/6dd4a7c29e48c3bc517bbdd7ed160624c36c2333)) +* **X:** Add `Open links as query` patch ([#2730](https://github.com/ReVanced/revanced-patches/issues/2730)) ([ba75a51](https://github.com/ReVanced/revanced-patches/commit/ba75a51b71dbb9157db230b3e97a90361019fe30)) +* **YouTube - Change header:** Improve patch option description ([3b8bc08](https://github.com/ReVanced/revanced-patches/commit/3b8bc08d4ed3a3a0f96d2f476e5059840b9f9d9b)) +* **YouTube - Change start page:** Add more start pages ([cc1d9b7](https://github.com/ReVanced/revanced-patches/commit/cc1d9b743633c619fb6acc428e884c1c9b53e10b)) +* **YouTube - Custom branding:** Improve patch option description ([e27f56c](https://github.com/ReVanced/revanced-patches/commit/e27f56c8a34d41167b290f47280276c1c6003876)) +* **YouTube - Spoof app version:** Add target versions ([#2787](https://github.com/ReVanced/revanced-patches/issues/2787)) ([83a7bd8](https://github.com/ReVanced/revanced-patches/commit/83a7bd8d69e62623fc4d2ba73d9fb49e92751d89)) +* **YouTube:** Reorganize settings menu ([#2737](https://github.com/ReVanced/revanced-patches/issues/2737)) ([36132df](https://github.com/ReVanced/revanced-patches/commit/36132df4be6a04c08b6f3dd79de1bcea93a80fb8)) + # [4.3.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.3.0-dev.12...v4.3.0-dev.13) (2024-03-02) diff --git a/gradle.properties b/gradle.properties index 40231653..d9f0d412 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0-dev.13 +version = 4.3.0 From e8b54bd0ecd013eef13b728d6c769970cdd7fe05 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Sat, 2 Mar 2024 08:29:39 +0100 Subject: [PATCH 50/52] build: Bump dependencies --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 7596f26a..a4c08e89 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,6 +1,6 @@ [versions] revanced-patcher = "19.3.1" -smali = "3.0.4" +smali = "3.0.5" guava = "33.0.0-jre" gson = "2.10.1" binary-compatibility-validator = "0.14.0" From 87887e4163dd9e242209f4d0fefb415f9bc7ca75 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 4 Mar 2024 14:59:32 +0100 Subject: [PATCH 51/52] feat(YouTube Vanced): Remove `Hide ads` patch --- .../youtubevanced/ad/general/HideAdsPatch.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/HideAdsPatch.kt index 229a5b9a..dcb3311c 100644 --- a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/HideAdsPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtubevanced.ad.general -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -9,17 +8,19 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.shared.misc.fix.verticalscroll.VerticalScrollPatch import app.revanced.patches.youtubevanced.ad.general.fingerprints.ContainsAdFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c +@Deprecated("This patch is going to be removed in the future.") @Patch( - name = "Hide ads", description = "Removes general ads.", dependencies = [VerticalScrollPatch::class], - compatiblePackages = [CompatiblePackage("com.vanced.android.youtube")] + compatiblePackages = [CompatiblePackage("com.vanced.android.youtube")], + use = false, ) @Suppress("unused") object HideAdsPatch : BytecodePatch( - setOf(ContainsAdFingerprint) + setOf(ContainsAdFingerprint), ) { override fun execute(context: BytecodeContext) { ContainsAdFingerprint.result?.let { result -> @@ -40,14 +41,14 @@ object HideAdsPatch : BytecodePatch( "hero_promo_image", "statement_banner", "primetime_promo", - "carousel_footered_layout" + "carousel_footered_layout", ).forEach { component -> addInstructions( insertIndex, """ const-string v$adsListRegister, "$component" invoke-interface {v0, v$adsListRegister}, Ljava/util/List;->add(Ljava/lang/Object;)Z - """ + """, ) } } From 816724457cba98c753d510098e8a28b11f401418 Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Mon, 4 Mar 2024 14:01:53 +0000 Subject: [PATCH 52/52] chore(release): 4.4.0-dev.1 [skip ci] # [4.4.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.3.0...v4.4.0-dev.1) (2024-03-04) ### Features * **YouTube Vanced:** Remove `Hide ads` patch ([87887e4](https://github.com/ReVanced/revanced-patches/commit/87887e4163dd9e242209f4d0fefb415f9bc7ca75)) --- CHANGELOG.md | 7 +++++++ gradle.properties | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd23acdc..edf24bbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.4.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v4.3.0...v4.4.0-dev.1) (2024-03-04) + + +### Features + +* **YouTube Vanced:** Remove `Hide ads` patch ([87887e4](https://github.com/ReVanced/revanced-patches/commit/87887e4163dd9e242209f4d0fefb415f9bc7ca75)) + # [4.3.0](https://github.com/ReVanced/revanced-patches/compare/v4.2.0...v4.3.0) (2024-03-02) diff --git a/gradle.properties b/gradle.properties index d9f0d412..c8118386 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 4.3.0 +version = 4.4.0-dev.1