diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 165c9c930e..93e7caf35d 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,16 +1,22 @@ version: 2 updates: - package-ecosystem: github-actions + labels: [] directory: / + target-branch: dev schedule: interval: monthly - package-ecosystem: npm + labels: [] directory: / + target-branch: dev schedule: interval: monthly - package-ecosystem: gradle + labels: [] directory: / + target-branch: dev schedule: interval: monthly diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7e5ddce21..4c4e7962ba 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,22 +24,21 @@ jobs: persist-credentials: false fetch-depth: 0 - - name: Cache Node modules - uses: actions/cache@v3 - with: - path: | - node_modules - key: npm-${{ hashFiles('package-lock.json') }} - - name: Cache Gradle uses: burrunan/gradle-cache-action@v1 - - name: Build with Gradle + - name: Build env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: ./gradlew generateMeta clean - - name: Setup semantic-release + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + cache: 'npm' + + - name: Install dependencies run: npm install - name: Release diff --git a/CHANGELOG.md b/CHANGELOG.md index 487506383a..e93925e379 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,137 @@ +# [4.0.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.14...v4.0.0-dev.15) (2024-01-27) + + +### Features + +* **Photomath:** Add `Hide update popup` patch ([#2637](https://github.com/ReVanced/revanced-patches/issues/2637)) ([fbbecd3](https://github.com/ReVanced/revanced-patches/commit/fbbecd33bbc92999d79d74f0abf54d129e3ee407)) + + +### BREAKING CHANGES + +* **Photomath:** Some packages have changed locations. + +# [4.0.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.13...v4.0.0-dev.14) (2024-01-27) + + +### Features + +* **YouTube - Spoof app version:** Add `18.09.39` to restore library tab ([#2643](https://github.com/ReVanced/revanced-patches/issues/2643)) ([dd108ff](https://github.com/ReVanced/revanced-patches/commit/dd108ff70f54c16694624ab30d3e1085ac0c215a)) + +# [4.0.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.12...v4.0.0-dev.13) (2024-01-27) + + +### Features + +* Move strings to resources for localization ([#2440](https://github.com/ReVanced/revanced-patches/issues/2440)) ([060ab8f](https://github.com/ReVanced/revanced-patches/commit/060ab8fbfeee212f9a93f52f4d24584f2c630047)) + + +### BREAKING CHANGES + +* Various APIs have been changed. + +# [4.0.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.11...v4.0.0-dev.12) (2024-01-24) + + +### Features + +* **YouTube:** Support version `19.03.35` ([#2640](https://github.com/ReVanced/revanced-patches/issues/2640)) ([ff08f58](https://github.com/ReVanced/revanced-patches/commit/ff08f58ac4ff4d66a8dce599caa1ce47f3366fc6)) + +# [4.0.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.10...v4.0.0-dev.11) (2024-01-17) + + +### Features + +* **YouTube:** Support version `19.02.34` ([#2627](https://github.com/ReVanced/revanced-patches/issues/2627)) ([94e08b7](https://github.com/ReVanced/revanced-patches/commit/94e08b74ced394abf9ae7d4fe6355bfe4d0be248)) + +# [4.0.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.9...v4.0.0-dev.10) (2024-01-16) + + +### Features + +* **YouTube:** Support versions `18.48.39`, `18.49.37` and `19.01.34` ([#2551](https://github.com/ReVanced/revanced-patches/issues/2551)) ([a938e73](https://github.com/ReVanced/revanced-patches/commit/a938e736fa2aed1792cfdce5656efa15d0791d71)) + +# [4.0.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.8...v4.0.0-dev.9) (2024-01-11) + + +### Bug Fixes + +* **YouTube - Enable slide to seek:** Change patch default to excluded and add description disclaimer ([#2610](https://github.com/ReVanced/revanced-patches/issues/2610)) ([2fdc4c2](https://github.com/ReVanced/revanced-patches/commit/2fdc4c23b5f39153ad71071359274c39129d691f)) + +# [4.0.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.7...v4.0.0-dev.8) (2024-01-10) + + +### Bug Fixes + +* **YouTube:** Shorten setting titles to fit on screen ([#2579](https://github.com/ReVanced/revanced-patches/issues/2579)) ([b2a5dd3](https://github.com/ReVanced/revanced-patches/commit/b2a5dd3efc39ae8a42159858b9c00b5b2f8655a4)) + +# [4.0.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.6...v4.0.0-dev.7) (2024-01-10) + + +### Bug Fixes + +* Use new integrations patch path ([51e2f3b](https://github.com/ReVanced/revanced-patches/commit/51e2f3b476b49460e2f3fc2b5f302a3a72d7963f)) + +# [4.0.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.5...v4.0.0-dev.6) (2024-01-09) + + +### Features + +* **Tiktok - Playback speed:** Remember playback speed ([#2506](https://github.com/ReVanced/revanced-patches/issues/2506)) ([d2970e5](https://github.com/ReVanced/revanced-patches/commit/d2970e54fbbd7e4b1ae1d354ae2d5c4bbe9336b0)) + +# [4.0.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.4...v4.0.0-dev.5) (2024-01-09) + + +### Bug Fixes + +* **YouTube - Change header:** Improve patch descriptions ([#2581](https://github.com/ReVanced/revanced-patches/issues/2581)) ([43a5677](https://github.com/ReVanced/revanced-patches/commit/43a5677397380f14a049ae95532fd5096b94c938)) + +# [4.0.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.3...v4.0.0-dev.4) (2024-01-09) + + +### Features + +* **MyFitnessPal:** Add `Hide ads` patch ([#2594](https://github.com/ReVanced/revanced-patches/issues/2594)) ([fd4b3c7](https://github.com/ReVanced/revanced-patches/commit/fd4b3c79a83f8de6256611629263d3e29e66f2c2)) + +# [4.0.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.2...v4.0.0-dev.3) (2024-01-09) + + +### Features + +* **Change package name:** Mention caveat of the patch in the description ([427b81a](https://github.com/ReVanced/revanced-patches/commit/427b81a79a5a1de79f14d2261059fb098b22227f)) + +# [4.0.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v4.0.0-dev.1...v4.0.0-dev.2) (2024-01-02) + + +### Features + +* **YouTube - Change header:** Change to ReVanced borderless logo header by default ([#2512](https://github.com/ReVanced/revanced-patches/issues/2512)) ([75f785d](https://github.com/ReVanced/revanced-patches/commit/75f785d1ef6026cbbdf7073c10aace1b28d93a30)) + +# [4.0.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v3.3.0-dev.2...v4.0.0-dev.1) (2024-01-01) + + +### Code Refactoring + +* Fix package and code structure ([#2541](https://github.com/ReVanced/revanced-patches/issues/2541)) ([a08457e](https://github.com/ReVanced/revanced-patches/commit/a08457e406f4b2e37458a4835c11d370a02d2ce6)) + + +### BREAKING CHANGES + +* Various public APIs have changed names and packages or were removed entirely + +# [3.3.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v3.3.0-dev.1...v3.3.0-dev.2) (2024-01-01) + + +### Features + +* **YouTube:** Improve patch descriptions ([#2519](https://github.com/ReVanced/revanced-patches/issues/2519)) ([e8d1389](https://github.com/ReVanced/revanced-patches/commit/e8d1389d3367b2fb688f0b85c136c512981b4fdc)) + +# [3.3.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v3.2.0...v3.3.0-dev.1) (2023-12-28) + + +### Features + +* **ID Austria:** Remove constraint on any version ([#2526](https://github.com/ReVanced/revanced-patches/issues/2526)) ([de2cb88](https://github.com/ReVanced/revanced-patches/commit/de2cb886169b3963b9ed70154bde0b7c6baaae40)) + # [3.2.0](https://github.com/ReVanced/revanced-patches/compare/v3.1.0...v3.2.0) (2023-12-28) diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 9a086a7838..8df98dba0b 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -4,7 +4,7 @@ public final class app/revanced/patches/all/activity/exportall/ExportAllActiviti public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } -public final class app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch : app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch { +public final class app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch; public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object; public fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Triple; @@ -38,7 +38,44 @@ public final class app/revanced/patches/all/misc/packagename/ChangePackageNamePa public final fun setOrGetFallbackPackageName (Ljava/lang/String;)Ljava/lang/String; } -public abstract class app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch : app/revanced/patcher/patch/BytecodePatch { +public final class app/revanced/patches/all/misc/resources/AddResourcesPatch : app/revanced/patcher/patch/ResourcePatch, java/io/Closeable, java/util/Map, kotlin/jvm/internal/markers/KMutableMap { + public static final field INSTANCE Lapp/revanced/patches/all/misc/resources/AddResourcesPatch; + public fun clear ()V + public fun close ()V + public final fun containsKey (Ljava/lang/Object;)Z + public fun containsKey (Ljava/lang/String;)Z + public final fun containsValue (Ljava/lang/Object;)Z + public fun containsValue (Ljava/util/Set;)Z + public final fun entrySet ()Ljava/util/Set; + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V + public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V + public final synthetic fun get (Ljava/lang/Object;)Ljava/lang/Object; + public final fun get (Ljava/lang/Object;)Ljava/util/Set; + public fun get (Ljava/lang/String;)Ljava/util/Set; + public fun getEntries ()Ljava/util/Set; + public fun getKeys ()Ljava/util/Set; + public fun getSize ()I + public fun getValues ()Ljava/util/Collection; + public final fun invoke (Ljava/lang/String;Lapp/revanced/util/resource/BaseResource;)Z + public final fun invoke (Ljava/lang/String;Ljava/lang/Iterable;)Z + public final fun invoke (Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;)Z + public final fun invoke (Ljava/lang/String;Ljava/util/List;)Z + public final fun invoke (Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;)Z + public static synthetic fun invoke$default (Lapp/revanced/patches/all/misc/resources/AddResourcesPatch;Ljava/lang/String;Ljava/lang/String;ZLjava/lang/String;ILjava/lang/Object;)Z + public static synthetic fun invoke$default (Lapp/revanced/patches/all/misc/resources/AddResourcesPatch;Lkotlin/reflect/KClass;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Z + public fun isEmpty ()Z + public final fun keySet ()Ljava/util/Set; + public synthetic fun put (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; + public fun put (Ljava/lang/String;Ljava/util/Set;)Ljava/util/Set; + public fun putAll (Ljava/util/Map;)V + public final synthetic fun remove (Ljava/lang/Object;)Ljava/lang/Object; + public final fun remove (Ljava/lang/Object;)Ljava/util/Set; + public fun remove (Ljava/lang/String;)Ljava/util/Set; + public final fun size ()I + public final fun values ()Ljava/util/Collection; +} + +public abstract class app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch : app/revanced/patcher/patch/BytecodePatch { public fun ()V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -59,7 +96,7 @@ public final class app/revanced/patches/all/misc/transformation/IMethodCall$Defa public static fun replaceInvokeVirtualWithIntegrations (Lapp/revanced/patches/all/misc/transformation/IMethodCall;Ljava/lang/String;Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;Lcom/android/tools/smali/dexlib2/iface/instruction/formats/Instruction35c;I)V } -public final class app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch : app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch { +public final class app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch; public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object; public fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Triple; @@ -80,7 +117,7 @@ public final class app/revanced/patches/all/screencapture/removerestriction/Remo public static fun values ()[Lapp/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch$MethodCall; } -public final class app/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch : app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch { +public final class app/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -103,7 +140,7 @@ public final class app/revanced/patches/all/screenshot/removerestriction/RemoveS public static fun values ()[Lapp/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch$MethodCall; } -public final class app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch : app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch { +public final class app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch; public synthetic fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Ljava/lang/Object; public fun filterMap (Lcom/android/tools/smali/dexlib2/iface/ClassDef;Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/iface/instruction/Instruction;I)Lkotlin/Pair; @@ -313,14 +350,18 @@ public final class app/revanced/patches/music/misc/gms/Constants { public static final field INSTANCE Lapp/revanced/patches/music/misc/gms/Constants; } -public final class app/revanced/patches/music/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportPatch { +public final class app/revanced/patches/music/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch { public static final field INSTANCE Lapp/revanced/patches/music/misc/gms/GmsCoreSupportPatch; } -public final class app/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch { +public final class app/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch { public static final field INSTANCE Lapp/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch; } +public final class app/revanced/patches/music/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { + public static final field INSTANCE Lapp/revanced/patches/music/misc/integrations/IntegrationsPatch; +} + public final class app/revanced/patches/music/premium/backgroundplay/BackgroundPlayPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/music/premium/backgroundplay/BackgroundPlayPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V @@ -333,6 +374,20 @@ public final class app/revanced/patches/myexpenses/misc/pro/UnlockProPatch : app public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } +public final class app/revanced/patches/myfitnesspal/ads/HideAdsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/myfitnesspal/ads/HideAdsPatch; + 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/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { + public static final field INSTANCE Lapp/revanced/patches/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint; +} + +public final class app/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { + public static final field INSTANCE Lapp/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint; +} + public final class app/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch : app/revanced/patcher/patch/ResourcePatch { public static final field INSTANCE Lapp/revanced/patches/netguard/broadcasts/removerestriction/RemoveBroadcastsRestrictionPatch; public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -363,8 +418,14 @@ public final class app/revanced/patches/photomath/detection/signature/SignatureD public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/photomath/misc/unlockplus/UnlockPlusPatch : app/revanced/patcher/patch/BytecodePatch { - public static final field INSTANCE Lapp/revanced/patches/photomath/misc/unlockplus/UnlockPlusPatch; +public final class app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch; + 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/photomath/misc/unlock/plus/UnlockPlusPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } @@ -393,7 +454,7 @@ public final class app/revanced/patches/reddit/ad/general/HideAdsPatch : app/rev public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public abstract class app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch : app/revanced/patcher/patch/BytecodePatch { +public abstract class app/revanced/patches/reddit/customclients/BaseSpoofClientPatch : app/revanced/patcher/patch/BytecodePatch { public fun (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V public synthetic fun (Ljava/lang/String;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V @@ -410,17 +471,17 @@ public final class app/revanced/patches/reddit/customclients/Constants { public static final field OAUTH_USER_AGENT Ljava/lang/String; } -public final class app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } -public final class app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } -public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } @@ -437,7 +498,7 @@ public final class app/revanced/patches/reddit/customclients/joeyforreddit/ads/D public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } @@ -448,19 +509,19 @@ public final class app/revanced/patches/reddit/customclients/joeyforreddit/detec public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchUserAgent (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } -public final class app/revanced/patches/reddit/customclients/relayforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/relayforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/relayforreddit/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchMiscellaneous (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } -public final class app/revanced/patches/reddit/customclients/slide/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/slide/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/slide/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V } @@ -477,7 +538,7 @@ public final class app/revanced/patches/reddit/customclients/syncforreddit/annoy public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/reddit/customclients/syncforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch { +public final class app/revanced/patches/reddit/customclients/syncforreddit/api/SpoofClientPatch : app/revanced/patches/reddit/customclients/BaseSpoofClientPatch { public static final field INSTANCE Lapp/revanced/patches/reddit/customclients/syncforreddit/api/SpoofClientPatch; public fun patchClientId (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V public fun patchMiscellaneous (Ljava/util/Set;Lapp/revanced/patcher/data/BytecodeContext;)V @@ -519,44 +580,62 @@ public final class app/revanced/patches/serviceportalbund/detection/root/RootDet public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/shared/fingerprints/HomeActivityFingerprint : app/revanced/patches/shared/integrations/AbstractIntegrationsPatch$IntegrationsFingerprint { - public static final field INSTANCE Lapp/revanced/patches/shared/fingerprints/HomeActivityFingerprint; +public final class app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + +public abstract class app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch : app/revanced/patcher/patch/BytecodePatch { + public fun (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lkotlin/reflect/KClass;Lapp/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Lkotlin/reflect/KClass;Lapp/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + +public abstract class app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch : app/revanced/patcher/patch/ResourcePatch { + public fun (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/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V + public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V + protected final fun getGmsCoreVendor ()Ljava/lang/String; } -public abstract class app/revanced/patches/shared/integrations/AbstractIntegrationsPatch : app/revanced/patcher/patch/BytecodePatch { +public abstract class app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch : app/revanced/patcher/patch/BytecodePatch { public fun (Ljava/lang/String;Ljava/util/Set;)V + public fun (Ljava/util/Set;)V public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public abstract class app/revanced/patches/shared/integrations/AbstractIntegrationsPatch$IntegrationsFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { +public abstract class app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch$IntegrationsFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { public fun ()V public fun (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;)V public synthetic fun (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function1;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun invoke (Ljava/lang/String;)V } -public abstract interface class app/revanced/patches/shared/integrations/AbstractIntegrationsPatch$IntegrationsFingerprint$RegisterResolver : kotlin/jvm/functions/Function1 { +public abstract interface class app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch$IntegrationsFingerprint$IRegisterResolver : kotlin/jvm/functions/Function1 { public abstract fun invoke (Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Integer; } -public final class app/revanced/patches/shared/integrations/AbstractIntegrationsPatch$IntegrationsFingerprint$RegisterResolver$DefaultImpls { - public static fun invoke (Lapp/revanced/patches/shared/integrations/AbstractIntegrationsPatch$IntegrationsFingerprint$RegisterResolver;Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Integer; +public final class app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch$IntegrationsFingerprint$IRegisterResolver$DefaultImpls { + public static fun invoke (Lapp/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch$IntegrationsFingerprint$IRegisterResolver;Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/lang/Integer; } -public final class app/revanced/patches/shared/mapping/misc/ResourceMappingPatch : app/revanced/patcher/patch/ResourcePatch { - public static final field INSTANCE Lapp/revanced/patches/shared/mapping/misc/ResourceMappingPatch; +public final class app/revanced/patches/shared/misc/mapping/ResourceMappingPatch : app/revanced/patcher/patch/ResourcePatch { + public static final field INSTANCE Lapp/revanced/patches/shared/misc/mapping/ResourceMappingPatch; public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } -public final class app/revanced/patches/shared/mapping/misc/ResourceMappingPatch$ResourceElement { +public final class app/revanced/patches/shared/misc/mapping/ResourceMappingPatch$ResourceElement { public fun (Ljava/lang/String;Ljava/lang/String;J)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Ljava/lang/String; public final fun component3 ()J - public final fun copy (Ljava/lang/String;Ljava/lang/String;J)Lapp/revanced/patches/shared/mapping/misc/ResourceMappingPatch$ResourceElement; - public static synthetic fun copy$default (Lapp/revanced/patches/shared/mapping/misc/ResourceMappingPatch$ResourceElement;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lapp/revanced/patches/shared/mapping/misc/ResourceMappingPatch$ResourceElement; + public final fun copy (Ljava/lang/String;Ljava/lang/String;J)Lapp/revanced/patches/shared/misc/mapping/ResourceMappingPatch$ResourceElement; + public static synthetic fun copy$default (Lapp/revanced/patches/shared/misc/mapping/ResourceMappingPatch$ResourceElement;Ljava/lang/String;Ljava/lang/String;JILjava/lang/Object;)Lapp/revanced/patches/shared/misc/mapping/ResourceMappingPatch$ResourceElement; public fun equals (Ljava/lang/Object;)Z public final fun getId ()J public final fun getName ()Ljava/lang/String; @@ -565,190 +644,175 @@ public final class app/revanced/patches/shared/mapping/misc/ResourceMappingPatch public fun toString ()Ljava/lang/String; } -public final class app/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch : app/revanced/patcher/patch/BytecodePatch { - public static final field INSTANCE Lapp/revanced/patches/shared/misc/fix/verticalscroll/VerticalScrollPatch; - public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V - public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V -} - -public abstract class app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportPatch : app/revanced/patcher/patch/BytecodePatch { - public fun (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Lapp/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patcher/fingerprint/MethodFingerprint;Ljava/util/Set;Lapp/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch;Ljava/util/Set;Ljava/util/Set;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V - public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V -} - -public abstract class app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch : app/revanced/patcher/patch/ResourcePatch { - public fun (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/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V - public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V - protected final fun getGmsCoreVendor ()Ljava/lang/String; -} - -public final class app/revanced/patches/shared/misc/gms/fingerprints/GmsCoreSupportFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { - public static final field GET_GMS_CORE_VENDOR_METHOD_NAME Ljava/lang/String; - public static final field INSTANCE Lapp/revanced/patches/shared/misc/gms/fingerprints/GmsCoreSupportFingerprint; -} - -public abstract class app/revanced/patches/shared/settings/AbstractSettingsResourcePatch : app/revanced/patcher/patch/ResourcePatch, java/io/Closeable { - public fun (Ljava/lang/String;Ljava/lang/String;)V +public abstract class app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch : app/revanced/patcher/patch/ResourcePatch, java/io/Closeable, java/util/Set, kotlin/jvm/internal/markers/KMutableSet { + public fun ()V + public fun (Lkotlin/Pair;Ljava/util/Set;)V + public synthetic fun (Lkotlin/Pair;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun add (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)Z + public synthetic fun add (Ljava/lang/Object;)Z + public fun addAll (Ljava/util/Collection;)Z + public fun clear ()V public fun close ()V + public fun contains (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)Z + public final fun contains (Ljava/lang/Object;)Z + public fun containsAll (Ljava/util/Collection;)Z public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V + public fun getSize ()I + public fun isEmpty ()Z + public fun iterator ()Ljava/util/Iterator; + public fun remove (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)Z + public final fun remove (Ljava/lang/Object;)Z + public fun removeAll (Ljava/util/Collection;)Z + public fun retainAll (Ljava/util/Collection;)Z + public final fun size ()I + public fun toArray ()[Ljava/lang/Object; + public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object; } -public abstract class app/revanced/patches/shared/settings/preference/BasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V +public abstract class app/revanced/patches/shared/misc/settings/preference/BasePreference { + public static final field Companion Lapp/revanced/patches/shared/misc/settings/preference/BasePreference$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z public final fun getKey ()Ljava/lang/String; - public final fun getSummary ()Lapp/revanced/patches/shared/settings/preference/impl/StringResource; + public final fun getSummaryKey ()Ljava/lang/String; public final fun getTag ()Ljava/lang/String; - public final fun getTitle ()Lapp/revanced/patches/shared/settings/preference/impl/StringResource; + public final fun getTitleKey ()Ljava/lang/String; + public fun hashCode ()I public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } -public abstract class app/revanced/patches/shared/settings/preference/BaseResource { - public fun (Ljava/lang/String;Ljava/lang/String;)V - public final fun getName ()Ljava/lang/String; - public final fun getTag ()Ljava/lang/String; - public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; - public static synthetic fun serialize$default (Lapp/revanced/patches/shared/settings/preference/BaseResource;Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lorg/w3c/dom/Element; +public final class app/revanced/patches/shared/misc/settings/preference/BasePreference$Companion { + public final fun addSummary (Lorg/w3c/dom/Element;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/SummaryType;)V + public static synthetic fun addSummary$default (Lapp/revanced/patches/shared/misc/settings/preference/BasePreference$Companion;Lorg/w3c/dom/Element;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/SummaryType;ILjava/lang/Object;)V } -public abstract class app/revanced/patches/shared/settings/preference/DefaultBasePreference : app/revanced/patches/shared/settings/preference/BasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;Ljava/lang/Object;)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;Ljava/lang/Object;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getDefault ()Ljava/lang/Object; - public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; +public abstract class app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen : java/io/Closeable { + public fun ()V + public fun (Ljava/util/Set;)V + public synthetic fun (Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun close ()V + public abstract fun commit (Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen;)V } -public final class app/revanced/patches/shared/settings/preference/SummaryType : java/lang/Enum { - public static final field DEFAULT Lapp/revanced/patches/shared/settings/preference/SummaryType; - public static final field OFF Lapp/revanced/patches/shared/settings/preference/SummaryType; - public static final field ON Lapp/revanced/patches/shared/settings/preference/SummaryType; +public abstract class app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$BasePreferenceCollection { + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getKey ()Ljava/lang/String; + public final fun getPreferences ()Ljava/util/Set; + public final fun getTitleKey ()Ljava/lang/String; + public abstract fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreference; +} + +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 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; + public fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/PreferenceScreen; +} + +public class app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen$Category : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$BasePreferenceCollection { + public fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V + public synthetic fun (Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen;Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun addPreferences ([Lapp/revanced/patches/shared/misc/settings/preference/BasePreference;)V + public synthetic fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreference; + public fun transform ()Lapp/revanced/patches/shared/misc/settings/preference/PreferenceCategory; +} + +public final class app/revanced/patches/shared/misc/settings/preference/InputType : java/lang/Enum { + public static final field NUMBER Lapp/revanced/patches/shared/misc/settings/preference/InputType; + public static final field TEXT Lapp/revanced/patches/shared/misc/settings/preference/InputType; + public static final field TEXT_CAP_CHARACTERS Lapp/revanced/patches/shared/misc/settings/preference/InputType; + public static final field TEXT_MULTI_LINE Lapp/revanced/patches/shared/misc/settings/preference/InputType; public static fun getEntries ()Lkotlin/enums/EnumEntries; public final fun getType ()Ljava/lang/String; - public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/settings/preference/SummaryType; - public static fun values ()[Lapp/revanced/patches/shared/settings/preference/SummaryType; + public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/InputType; + public static fun values ()[Lapp/revanced/patches/shared/misc/settings/preference/InputType; } -public final class app/revanced/patches/shared/settings/preference/impl/ArrayResource : app/revanced/patches/shared/settings/preference/BaseResource { - public fun (Ljava/lang/String;Ljava/util/List;)V - public final fun getItems ()Ljava/util/List; +public final class app/revanced/patches/shared/misc/settings/preference/IntentPreference : app/revanced/patches/shared/misc/settings/preference/BasePreference { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getIntent ()Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent; + public fun hashCode ()I public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } -public final class app/revanced/patches/shared/settings/preference/impl/InputType : java/lang/Enum { - public static final field NUMBER Lapp/revanced/patches/shared/settings/preference/impl/InputType; - public static final field TEXT Lapp/revanced/patches/shared/settings/preference/impl/InputType; - public static final field TEXT_CAP_CHARACTERS Lapp/revanced/patches/shared/settings/preference/impl/InputType; - public static final field TEXT_MULTI_LINE Lapp/revanced/patches/shared/settings/preference/impl/InputType; - public static fun getEntries ()Lkotlin/enums/EnumEntries; - public final fun getType ()Ljava/lang/String; - public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/settings/preference/impl/InputType; - public static fun values ()[Lapp/revanced/patches/shared/settings/preference/impl/InputType; +public final class app/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent { + public fun (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)V + public final fun copy (Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function0;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent; + public static synthetic fun copy$default (Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function0;ILjava/lang/Object;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; } -public final class app/revanced/patches/shared/settings/preference/impl/ListPreference : app/revanced/patches/shared/settings/preference/DefaultBasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource;Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource;Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getEntries ()Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource; - public final fun getEntryValues ()Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource; +public final class app/revanced/patches/shared/misc/settings/preference/ListPreference : app/revanced/patches/shared/misc/settings/preference/BasePreference { + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/util/resource/ArrayResource;Lapp/revanced/util/resource/ArrayResource;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/util/resource/ArrayResource;Lapp/revanced/util/resource/ArrayResource;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getEntries ()Lapp/revanced/util/resource/ArrayResource; + public final fun getEntriesKey ()Ljava/lang/String; + public final fun getEntryValues ()Lapp/revanced/util/resource/ArrayResource; + public final fun getEntryValuesKey ()Ljava/lang/String; public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } -public final class app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference : app/revanced/patches/shared/settings/preference/BasePreference { - public fun (Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;Z)V - public synthetic fun (Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V +public final class app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference : app/revanced/patches/shared/misc/settings/preference/BasePreference { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Z)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getSelectable ()Z public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } -public final class app/revanced/patches/shared/settings/preference/impl/Preference : app/revanced/patches/shared/settings/preference/BasePreference { - public fun (Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/Preference$Intent;)V - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/Preference$Intent;)V - public final fun getIntent ()Lapp/revanced/patches/shared/settings/preference/impl/Preference$Intent; - public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; -} - -public final class app/revanced/patches/shared/settings/preference/impl/Preference$Intent { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V -} - -public class app/revanced/patches/shared/settings/preference/impl/PreferenceCategory : app/revanced/patches/shared/settings/preference/BasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/util/List;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getPreferences ()Ljava/util/List; - public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; - public final fun setPreferences (Ljava/util/List;)V -} - -public class app/revanced/patches/shared/settings/preference/impl/PreferenceScreen : app/revanced/patches/shared/settings/preference/BasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/util/List;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Ljava/util/List;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getPreferences ()Ljava/util/List; +public class app/revanced/patches/shared/misc/settings/preference/PreferenceCategory : app/revanced/patches/shared/misc/settings/preference/BasePreference { + public fun (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/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 fun setPreferences (Ljava/util/List;)V } -public final class app/revanced/patches/shared/settings/preference/impl/StringResource : app/revanced/patches/shared/settings/preference/BaseResource { - public fun (Ljava/lang/String;Ljava/lang/String;Z)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getFormatted ()Z - public final fun getValue ()Ljava/lang/String; +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 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/settings/preference/impl/SwitchPreference : app/revanced/patches/shared/settings/preference/DefaultBasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Z)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getSummaryOff ()Lapp/revanced/patches/shared/settings/preference/impl/StringResource; - public final fun getSummaryOn ()Lapp/revanced/patches/shared/settings/preference/impl/StringResource; - public final fun getUserDialogMessage ()Lapp/revanced/patches/shared/settings/preference/impl/StringResource; - 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/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; + public static final field ON Lapp/revanced/patches/shared/misc/settings/preference/SummaryType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; + public final fun getType ()Ljava/lang/String; + public static fun valueOf (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/SummaryType; + public static fun values ()[Lapp/revanced/patches/shared/misc/settings/preference/SummaryType; } -public final class app/revanced/patches/shared/settings/preference/impl/TextPreference : app/revanced/patches/shared/settings/preference/DefaultBasePreference { - public fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/InputType;Ljava/lang/String;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/StringResource;Lapp/revanced/patches/shared/settings/preference/impl/InputType;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getInputType ()Lapp/revanced/patches/shared/settings/preference/impl/InputType; +public final class app/revanced/patches/shared/misc/settings/preference/SwitchPreference : app/revanced/patches/shared/misc/settings/preference/BasePreference { + public fun ()V + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getSummaryOffKey ()Ljava/lang/String; + public final fun getSummaryOnKey ()Ljava/lang/String; public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } -public abstract class app/revanced/patches/shared/settings/util/AbstractPreferenceScreen : java/io/Closeable { +public final class app/revanced/patches/shared/misc/settings/preference/TextPreference : app/revanced/patches/shared/misc/settings/preference/BasePreference { public fun ()V - public fun (Ljava/util/List;)V - public synthetic fun (Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public fun close ()V - public abstract fun commit (Lapp/revanced/patches/shared/settings/preference/impl/PreferenceScreen;)V -} - -public abstract class app/revanced/patches/shared/settings/util/AbstractPreferenceScreen$BasePreferenceCollection { - public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getKey ()Ljava/lang/String; - public final fun getPreferences ()Ljava/util/List; - public final fun getTitle ()Ljava/lang/String; - public abstract fun transform ()Lapp/revanced/patches/shared/settings/preference/BasePreference; -} - -public class app/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen : app/revanced/patches/shared/settings/util/AbstractPreferenceScreen$BasePreferenceCollection { - public fun (Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;)V - public synthetic fun (Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun addPreferences ([Lapp/revanced/patches/shared/settings/preference/BasePreference;)V - public final fun getCategories ()Ljava/util/List; - public final fun getSummary ()Ljava/lang/String; - public synthetic fun transform ()Lapp/revanced/patches/shared/settings/preference/BasePreference; - public fun transform ()Lapp/revanced/patches/shared/settings/preference/impl/PreferenceScreen; -} - -public class app/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen$Category : app/revanced/patches/shared/settings/util/AbstractPreferenceScreen$BasePreferenceCollection { - public fun (Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;)V - public synthetic fun (Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun addPreferences ([Lapp/revanced/patches/shared/settings/preference/BasePreference;)V - public synthetic fun transform ()Lapp/revanced/patches/shared/settings/preference/BasePreference; - public fun transform ()Lapp/revanced/patches/shared/settings/preference/impl/PreferenceCategory; + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/InputType;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lapp/revanced/patches/shared/misc/settings/preference/InputType;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getInputType ()Lapp/revanced/patches/shared/misc/settings/preference/InputType; + public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; } public final class app/revanced/patches/solidexplorer2/functionality/filesize/RemoveFileSizeLimitPatch : app/revanced/patcher/patch/BytecodePatch { @@ -842,7 +906,7 @@ public final class app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPa public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/tiktok/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/integrations/AbstractIntegrationsPatch { +public final class app/revanced/patches/tiktok/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { public static final field INSTANCE Lapp/revanced/patches/tiktok/misc/integrations/IntegrationsPatch; } @@ -936,25 +1000,25 @@ public final class app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch : ap public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public abstract class app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch : app/revanced/patcher/patch/BytecodePatch { +public abstract class app/revanced/patches/twitch/ad/shared/util/BaseAdPatch : app/revanced/patcher/patch/BytecodePatch { public fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/util/Set;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - protected final fun blockMethods (Lapp/revanced/patcher/data/BytecodeContext;Ljava/lang/String;[Ljava/lang/String;Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch$ReturnMethod;)Z - public static synthetic fun blockMethods$default (Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch;Lapp/revanced/patcher/data/BytecodeContext;Ljava/lang/String;[Ljava/lang/String;Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch$ReturnMethod;ILjava/lang/Object;)Z + protected final fun blockMethods (Lapp/revanced/patcher/data/BytecodeContext;Ljava/lang/String;[Ljava/lang/String;Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch$ReturnMethod;)Z + public static synthetic fun blockMethods$default (Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch;Lapp/revanced/patcher/data/BytecodeContext;Ljava/lang/String;[Ljava/lang/String;Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch$ReturnMethod;ILjava/lang/Object;)Z protected final fun createConditionInstructions (Ljava/lang/String;)Ljava/lang/String; - public static synthetic fun createConditionInstructions$default (Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String; + public static synthetic fun createConditionInstructions$default (Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch;Ljava/lang/String;ILjava/lang/Object;)Ljava/lang/String; public final fun getConditionCall ()Ljava/lang/String; public final fun getSkipLabelName ()Ljava/lang/String; } -protected final class app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch$ReturnMethod { +protected final class app/revanced/patches/twitch/ad/shared/util/BaseAdPatch$ReturnMethod { public fun ()V public fun (CLjava/lang/String;)V public synthetic fun (CLjava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()C public final fun component2 ()Ljava/lang/String; - public final fun copy (CLjava/lang/String;)Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch$ReturnMethod; - public static synthetic fun copy$default (Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch$ReturnMethod;CLjava/lang/String;ILjava/lang/Object;)Lapp/revanced/patches/twitch/ad/shared/util/AbstractAdPatch$ReturnMethod; + public final fun copy (CLjava/lang/String;)Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch$ReturnMethod; + public static synthetic fun copy$default (Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch$ReturnMethod;CLjava/lang/String;ILjava/lang/Object;)Lapp/revanced/patches/twitch/ad/shared/util/BaseAdPatch$ReturnMethod; public fun equals (Ljava/lang/Object;)Z public final fun getReturnType ()C public final fun getValue ()Ljava/lang/String; @@ -962,7 +1026,7 @@ protected final class app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch public fun toString ()Ljava/lang/String; } -public final class app/revanced/patches/twitch/ad/video/VideoAdsPatch : app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch { +public final class app/revanced/patches/twitch/ad/video/VideoAdsPatch : app/revanced/patches/twitch/ad/shared/util/BaseAdPatch { public static final field INSTANCE Lapp/revanced/patches/twitch/ad/video/VideoAdsPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -974,8 +1038,8 @@ public final class app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessag public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointPatch : app/revanced/patcher/patch/BytecodePatch { - public static final field INSTANCE Lapp/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointPatch; +public final class app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } @@ -986,25 +1050,19 @@ public final class app/revanced/patches/twitch/debug/DebugModePatch : app/revanc public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/twitch/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/integrations/AbstractIntegrationsPatch { +public final class app/revanced/patches/twitch/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { public static final field INSTANCE Lapp/revanced/patches/twitch/misc/integrations/IntegrationsPatch; } public final class app/revanced/patches/twitch/misc/settings/SettingsPatch : app/revanced/patcher/patch/BytecodePatch, java/io/Closeable { public static final field INSTANCE Lapp/revanced/patches/twitch/misc/settings/SettingsPatch; - public final fun addPreferenceScreen (Lapp/revanced/patches/shared/settings/preference/impl/PreferenceScreen;)V - public final fun addString (Ljava/lang/String;Ljava/lang/String;Z)V - public static synthetic fun addString$default (Lapp/revanced/patches/twitch/misc/settings/SettingsPatch;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)V public fun close ()V 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/twitch/misc/settings/SettingsResourcePatch : app/revanced/patches/shared/settings/AbstractSettingsResourcePatch { +public final class app/revanced/patches/twitch/misc/settings/SettingsResourcePatch : app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch { public static final field INSTANCE Lapp/revanced/patches/twitch/misc/settings/SettingsResourcePatch; - public final fun addArray (Lapp/revanced/patches/shared/settings/preference/impl/ArrayResource;)V - public final fun addPreferenceScreen (Lapp/revanced/patches/shared/settings/preference/impl/PreferenceScreen;)V - public final fun addString (Ljava/lang/String;Ljava/lang/String;Z)V } public final class app/revanced/patches/twitter/misc/dynamiccolor/DynamicColorPatch : app/revanced/patcher/patch/ResourcePatch { @@ -1020,17 +1078,17 @@ public final class app/revanced/patches/twitter/misc/hook/json/JsonHookPatch : a public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public abstract class app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch : app/revanced/patcher/patch/BytecodePatch { +public abstract class app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch : app/revanced/patcher/patch/BytecodePatch { public fun (Ljava/lang/String;)V 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/twitter/misc/hook/patch/ads/HideAdsPatch : app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch { - public static final field INSTANCE Lapp/revanced/patches/twitter/misc/hook/patch/ads/HideAdsPatch; +public final class app/revanced/patches/twitter/misc/hook/patch/ads/HideAdsHookPatch : app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch { + public static final field INSTANCE Lapp/revanced/patches/twitter/misc/hook/patch/ads/HideAdsHookPatch; } -public final class app/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch : app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch { +public final class app/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch : app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch { public static final field INSTANCE Lapp/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch; } @@ -1136,6 +1194,12 @@ public final class app/revanced/patches/youtube/layout/branding/CustomBrandingPa public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } +public final class app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch : app/revanced/patcher/patch/ResourcePatch { + public static final field INSTANCE Lapp/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch; + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V + public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V +} + public final class app/revanced/patches/youtube/layout/branding/header/PremiumHeadingPatch : app/revanced/patcher/patch/ResourcePatch { public static final field INSTANCE Lapp/revanced/patches/youtube/layout/branding/header/PremiumHeadingPatch; public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -1250,12 +1314,6 @@ public final class app/revanced/patches/youtube/layout/hide/loadmorebutton/HideL public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressPatch : app/revanced/patcher/patch/BytecodePatch { - public static final field INSTANCE Lapp/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressPatch; - 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/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch : app/revanced/patcher/patch/ResourcePatch { public static final field INSTANCE Lapp/revanced/patches/youtube/layout/hide/player/flyoutmenupanel/HidePlayerFlyoutMenuPatch; public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -1429,19 +1487,17 @@ public final class app/revanced/patches/youtube/misc/fix/playback/SpoofSignature public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } -public final class app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportPatch { +public final class app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch; - 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/youtube/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch { +public final class app/revanced/patches/youtube/misc/gms/GmsCoreSupportResourcePatch : app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/gms/GmsCoreSupportResourcePatch; public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } -public final class app/revanced/patches/youtube/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/integrations/AbstractIntegrationsPatch { +public final class app/revanced/patches/youtube/misc/integrations/IntegrationsPatch : app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/integrations/IntegrationsPatch; } @@ -1451,7 +1507,7 @@ public final class app/revanced/patches/youtube/misc/links/BypassURLRedirectsPat public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V } -public final class app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch : app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch { +public final class app/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch : app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/links/OpenLinksExternallyPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V @@ -1513,30 +1569,24 @@ public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQuery public final class app/revanced/patches/youtube/misc/settings/SettingsPatch : app/revanced/patcher/patch/BytecodePatch, java/io/Closeable { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/settings/SettingsPatch; - public final fun addPreference (Lapp/revanced/patches/shared/settings/preference/impl/Preference;)V - public final fun addPreferenceScreen (Lapp/revanced/patches/shared/settings/preference/impl/PreferenceScreen;)V - public final fun addString (Ljava/lang/String;Ljava/lang/String;Z)V - public static synthetic fun addString$default (Lapp/revanced/patches/youtube/misc/settings/SettingsPatch;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)V public fun close ()V - public final fun createReVancedSettingsIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/settings/preference/impl/Preference$Intent; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V - public final fun renameIntentsTargetPackage (Ljava/lang/String;)V + public final fun newIntent (Ljava/lang/String;)Lapp/revanced/patches/shared/misc/settings/preference/IntentPreference$Intent; } -public final class app/revanced/patches/youtube/misc/settings/SettingsPatch$PreferenceScreen : app/revanced/patches/shared/settings/util/AbstractPreferenceScreen { +public final class app/revanced/patches/youtube/misc/settings/SettingsPatch$PreferenceScreen : app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/settings/SettingsPatch$PreferenceScreen; - public fun commit (Lapp/revanced/patches/shared/settings/preference/impl/PreferenceScreen;)V - public final fun getADS ()Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen; - public final fun getINTERACTIONS ()Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen; - public final fun getLAYOUT ()Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen; - public final fun getMISC ()Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen; - public final fun getVIDEO ()Lapp/revanced/patches/shared/settings/util/AbstractPreferenceScreen$Screen; + 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 getMISC ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; + public final fun getVIDEO ()Lapp/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen$Screen; } -public final class app/revanced/patches/youtube/misc/settings/SettingsResourcePatch : app/revanced/patches/shared/settings/AbstractSettingsResourcePatch { +public final class app/revanced/patches/youtube/misc/settings/SettingsResourcePatch : app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch { public static final field INSTANCE Lapp/revanced/patches/youtube/misc/settings/SettingsResourcePatch; - public fun close ()V public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V public fun execute (Lapp/revanced/patcher/data/ResourceContext;)V } @@ -1661,11 +1711,13 @@ public final class app/revanced/util/ResourceGroup { } 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/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 public static final fun iterateXmlNodeChildren (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;)V - public static final fun mergeStrings (Lapp/revanced/patcher/data/ResourceContext;Ljava/lang/String;)V } public abstract class app/revanced/util/patch/LiteralValueFingerprint : app/revanced/patcher/fingerprint/MethodFingerprint { @@ -1673,3 +1725,37 @@ public abstract class app/revanced/util/patch/LiteralValueFingerprint : app/reva public synthetic fun (Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Iterable;Ljava/lang/Iterable;Ljava/lang/Iterable;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V } +public final class app/revanced/util/resource/ArrayResource : app/revanced/util/resource/BaseResource { + public static final field Companion Lapp/revanced/util/resource/ArrayResource$Companion; + public fun (Ljava/lang/String;Ljava/util/List;)V + public final fun getItems ()Ljava/util/List; + public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; +} + +public final class app/revanced/util/resource/ArrayResource$Companion { + public final fun fromNode (Lorg/w3c/dom/Node;)Lapp/revanced/util/resource/ArrayResource; +} + +public abstract class app/revanced/util/resource/BaseResource { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public fun equals (Ljava/lang/Object;)Z + public final fun getName ()Ljava/lang/String; + public final fun getTag ()Ljava/lang/String; + public fun hashCode ()I + public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; + public static synthetic fun serialize$default (Lapp/revanced/util/resource/BaseResource;Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lorg/w3c/dom/Element; +} + +public final class app/revanced/util/resource/StringResource : app/revanced/util/resource/BaseResource { + public static final field Companion Lapp/revanced/util/resource/StringResource$Companion; + public fun (Ljava/lang/String;Ljava/lang/String;Z)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun getFormatted ()Z + public final fun getValue ()Ljava/lang/String; + public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element; +} + +public final class app/revanced/util/resource/StringResource$Companion { + public final fun fromNode (Lorg/w3c/dom/Node;)Lapp/revanced/util/resource/StringResource; +} + diff --git a/build.gradle.kts b/build.gradle.kts index b98f2cf184..9c0f5574cd 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,7 +1,7 @@ import org.gradle.kotlin.dsl.support.listFilesOrdered plugins { - kotlin("jvm") version "1.9.21" + kotlin("jvm") version "1.9.22" alias(libs.plugins.binary.compatibility.validator) `maven-publish` } @@ -78,7 +78,7 @@ tasks { dependsOn(build) classpath = sourceSets["main"].runtimeClasspath - mainClass.set("app.revanced.meta.PatchesFileGenerator") + mainClass.set("app.revanced.meta.IPatchesFileGenerator") } // Required to run tasks because Gradle semantic-release plugin runs the publish task. diff --git a/gradle.properties b/gradle.properties index 1cafda7a3c..3a082331c1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 3.2.0 +version = 4.0.0-dev.15 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fe1189f832..8da2c1cb7a 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] -revanced-patcher = "19.1.0" +revanced-patcher = "19.2.0" smali = "3.0.3" -guava = "32.1.3-jre" +guava = "33.0.0-jre" gson = "2.10.1" binary-compatibility-validator = "0.13.2" diff --git a/package-lock.json b/package-lock.json index 825662bd52..29e79ed213 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,14 +8,14 @@ "@saithodev/semantic-release-backmerge": "^4.0.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", - "gradle-semantic-release-plugin": "^1.8.0", - "semantic-release": "^22.0.12" + "gradle-semantic-release-plugin": "^1.9.1", + "semantic-release": "^23.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { "@babel/highlight": "^7.23.4", @@ -66,15 +66,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/@babel/code-frame/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -160,15 +151,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -245,9 +227,9 @@ } }, "node_modules/@octokit/core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.0.1.tgz", - "integrity": "sha512-lyeeeZyESFo+ffI801SaBKmCfsvarO+dgV8/0gD8u1d87clbEdWsP5yC+dSj3zLhb2eIf5SJrn6vDz9AheETHw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz", + "integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==", "dev": true, "dependencies": { "@octokit/auth-token": "^4.0.0", @@ -263,13 +245,12 @@ } }, "node_modules/@octokit/endpoint": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.2.tgz", - "integrity": "sha512-qhKW8YLIi+Kmc92FQUFGr++DYtkx/1fBv+Thua6baqnjnOsgBYJDCvWZR1YcINuHGOEQt416WOfE+A/oG60NBQ==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", + "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", "dev": true, "dependencies": { "@octokit/types": "^12.0.0", - "is-plain-object": "^5.0.0", "universal-user-agent": "^6.0.0" }, "engines": { @@ -291,18 +272,18 @@ } }, "node_modules/@octokit/openapi-types": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.0.2.tgz", - "integrity": "sha512-8li32fUDUeml/ACRp/njCWTsk5t17cfTM1jp9n08pBrqs5cDFJubtjsSnuz56r5Tad6jdEPJld7LxNp9dNcyjQ==", + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", + "integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==", "dev": true }, "node_modules/@octokit/plugin-paginate-rest": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.4.tgz", - "integrity": "sha512-MvZx4WvfhBnt7PtH5XE7HORsO7bBk4er1FgRIUr1qJ89NR2I6bWjGyKsxk8z42FPQ34hFQm0Baanh4gzdZR4gQ==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.5.tgz", + "integrity": "sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==", "dev": true, "dependencies": { - "@octokit/types": "^12.3.0" + "@octokit/types": "^12.4.0" }, "engines": { "node": ">= 18" @@ -345,15 +326,14 @@ } }, "node_modules/@octokit/request": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.5.tgz", - "integrity": "sha512-zVKbNbX1xUluD9ZR4/tPs1yuYrK9xeh5fGZUXA6u04XGsTvomg0YO8/ZUC0FqAd49hAOEMFPAVUTh+2lBhOhLA==", + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", + "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", "dev": true, "dependencies": { "@octokit/endpoint": "^9.0.0", "@octokit/request-error": "^5.0.0", "@octokit/types": "^12.0.0", - "is-plain-object": "^5.0.0", "universal-user-agent": "^6.0.0" }, "engines": { @@ -375,12 +355,12 @@ } }, "node_modules/@octokit/types": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.3.0.tgz", - "integrity": "sha512-nJ8X2HRr234q3w/FcovDlA+ttUU4m1eJAourvfUUtwAWeqL8AsyRqfnLvVnYn3NFbUnsmzQCzLNdFerPwdmcDQ==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz", + "integrity": "sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==", "dev": true, "dependencies": { - "@octokit/openapi-types": "^19.0.2" + "@octokit/openapi-types": "^19.1.0" } }, "node_modules/@pnpm/config.env-replace": { @@ -410,32 +390,371 @@ "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, - "node_modules/@pnpm/npm-conf": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", - "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@saithodev/semantic-release-backmerge": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@saithodev/semantic-release-backmerge/-/semantic-release-backmerge-4.0.1.tgz", + "integrity": "sha512-WDsU28YrXSLx0xny7FgFlEk8DCKGcj6OOhA+4Q9k3te1jJD1GZuqY8sbIkVQaw9cqJ7CT+fCZUN6QDad8JW4Dg==", + "dev": true, + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.1.0", + "debug": "^4.3.4", + "execa": "^5.1.1", + "lodash": "^4.17.21", + "semantic-release": "^22.0.7" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/env-ci": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-10.0.0.tgz", + "integrity": "sha512-U4xcd/utDYFgMh0yWj07R1H6L5fwhVbmxBCpnL0DbVSDZVnsC82HONw0wxtxNkIAcua3KtbomQvIk5xFZGAQJw==", + "dev": true, + "dependencies": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/env-ci/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/env-ci/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/marked": { + "version": "9.1.6", + "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", + "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, + "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", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/npm-run-path": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "dev": true, + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/semantic-release": { + "version": "22.0.12", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-22.0.12.tgz", + "integrity": "sha512-0mhiCR/4sZb00RVFJIUlMuiBkW3NMpVIW2Gse7noqEMoFGkvfPPAImEQbkBV8xga4KOPP4FdTRYuLLy32R1fPw==", + "dev": true, + "dependencies": { + "@semantic-release/commit-analyzer": "^11.0.0", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^9.0.0", + "@semantic-release/npm": "^11.0.0", + "@semantic-release/release-notes-generator": "^12.0.0", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^8.0.0", + "debug": "^4.0.0", + "env-ci": "^10.0.0", + "execa": "^8.0.0", + "figures": "^6.0.0", + "find-versions": "^5.1.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^3.0.0", + "hosted-git-info": "^7.0.0", + "import-from-esm": "^1.3.1", + "lodash-es": "^4.17.21", + "marked": "^9.0.0", + "marked-terminal": "^6.0.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-pkg-up": "^11.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^4.0.0", + "signale": "^1.2.1", + "yargs": "^17.5.1" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/semantic-release/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/semantic-release/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/semantic-release/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/semantic-release/node_modules/execa/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@saithodev/semantic-release-backmerge/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "dependencies": { - "@pnpm/config.env-replace": "^1.1.0", - "@pnpm/network.ca-file": "^1.0.1", - "config-chain": "^1.1.11" - }, "engines": { - "node": ">=12" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@saithodev/semantic-release-backmerge": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@saithodev/semantic-release-backmerge/-/semantic-release-backmerge-4.0.1.tgz", - "integrity": "sha512-WDsU28YrXSLx0xny7FgFlEk8DCKGcj6OOhA+4Q9k3te1jJD1GZuqY8sbIkVQaw9cqJ7CT+fCZUN6QDad8JW4Dg==", + "node_modules/@saithodev/semantic-release-backmerge/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "dependencies": { - "@semantic-release/error": "^3.0.0", - "aggregate-error": "^3.1.0", - "debug": "^4.3.4", - "execa": "^5.1.1", - "lodash": "^4.17.21", - "semantic-release": "^22.0.7" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@semantic-release/changelog": { @@ -509,9 +828,9 @@ } }, "node_modules/@semantic-release/github": { - "version": "9.2.3", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.2.3.tgz", - "integrity": "sha512-FAjXb1F84CVI6IG8fWi+XS9ErYD+s3MHkP03zBa3+GyUrV4kqwYu/WPppIciHxujGFR51SAWPkOY5rnH6ZlrxA==", + "version": "9.2.6", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-9.2.6.tgz", + "integrity": "sha512-shi+Lrf6exeNZF+sBhK+P011LSbhmIAoUEgEY6SsxF8irJ+J2stwI5jkyDQ+4gzYyDImzV6LCKdYB9FXnQRWKA==", "dev": true, "dependencies": { "@octokit/core": "^5.0.0", @@ -527,8 +846,8 @@ "https-proxy-agent": "^7.0.0", "issue-parser": "^6.0.0", "lodash-es": "^4.17.21", - "mime": "^3.0.0", - "p-filter": "^3.0.0", + "mime": "^4.0.0", + "p-filter": "^4.0.0", "url-join": "^5.0.0" }, "engines": { @@ -578,6 +897,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@semantic-release/github/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@semantic-release/github/node_modules/indent-string": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", @@ -591,9 +922,9 @@ } }, "node_modules/@semantic-release/npm": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.1.tgz", - "integrity": "sha512-nFcT0pgVwpXsPkzjqP3ObH+pILeN1AbYscCDuYwgZEPZukL+RsGhrtdT4HA1Gjb/y1bVbE90JNtMIcgRi5z/Fg==", + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-11.0.2.tgz", + "integrity": "sha512-owtf3RjyPvRE63iUKZ5/xO4uqjRpVQDUB9+nnXj0xwfIeM9pRl+cG+zGDzdftR4m3f2s4Wyf3SexW+kF5DFtWA==", "dev": true, "dependencies": { "@semantic-release/error": "^4.0.0", @@ -657,6 +988,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@semantic-release/npm/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@semantic-release/npm/node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -738,9 +1081,9 @@ } }, "node_modules/@semantic-release/npm/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -1166,21 +1509,29 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "dependencies": { - "import-fresh": "^3.2.1", + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" + "parse-json": "^5.2.0" }, "engines": { "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/cross-spawn": { @@ -1302,9 +1653,9 @@ "dev": true }, "node_modules/env-ci": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-10.0.0.tgz", - "integrity": "sha512-U4xcd/utDYFgMh0yWj07R1H6L5fwhVbmxBCpnL0DbVSDZVnsC82HONw0wxtxNkIAcua3KtbomQvIk5xFZGAQJw==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.0.0.tgz", + "integrity": "sha512-apikxMgkipkgTvMdRT9MNqWx5VLOci79F4VBd7Op/7OPjjoanjdAvn6fglMCCEf/1bAh8eOiuEVCUs4V3qP3nQ==", "dev": true, "dependencies": { "execa": "^8.0.0", @@ -1383,9 +1734,9 @@ } }, "node_modules/env-ci/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -1448,6 +1799,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -1467,15 +1827,12 @@ } }, "node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/esprima": { @@ -1531,9 +1888,9 @@ } }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -1566,6 +1923,18 @@ "node": ">=8" } }, + "node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/find-up-simple": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", @@ -1604,9 +1973,9 @@ } }, "node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -1670,16 +2039,6 @@ "through2": "~2.0.0" } }, - "node_modules/git-log-parser/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -1731,9 +2090,9 @@ "dev": true }, "node_modules/gradle-semantic-release-plugin": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.8.0.tgz", - "integrity": "sha512-lRoKlLJvQbvRykDf6nWVuf/XyHEO9TL8dcnLX9lDag8zn5tkOqp5Tctb4re1YEek0zsSVAVX/1nw5lkV5pfm/Q==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/gradle-semantic-release-plugin/-/gradle-semantic-release-plugin-1.9.1.tgz", + "integrity": "sha512-lCrw22itszP/FLSL3N61E40vH1+CU95/4LG9ZF+Fxr8tcx7EPthh2eqVPAq67udFlM8ZgO2LETnn8LSDRq1J2w==", "dev": true, "funding": [ { @@ -1742,14 +2101,14 @@ } ], "dependencies": { - "promisified-properties": "^2.0.27", + "promisified-properties": "^3.0.0", "split2": "^4.1.0" }, "engines": { "node": ">=18" }, "peerDependencies": { - "semantic-release": "^22.0.5" + "semantic-release": "^23.0.0" } }, "node_modules/handlebars": { @@ -2025,15 +2384,6 @@ "node": ">=8" } }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -2214,6 +2564,19 @@ "node": ">=4" } }, + "node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -2257,44 +2620,44 @@ "dev": true }, "node_modules/lru-cache": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.3.tgz", - "integrity": "sha512-B7gr+F6MkqB3uzINHXNctGieGsRTMwIBgxkp0yq/5BwcuDzD4A8wQpHQW6vDAm1uKSLQghmRdD9sKqf2vJ1cEg==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", "dev": true, "engines": { "node": "14 || >=16.14" } }, "node_modules/marked": { - "version": "9.1.6", - "resolved": "https://registry.npmjs.org/marked/-/marked-9.1.6.tgz", - "integrity": "sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-11.1.1.tgz", + "integrity": "sha512-EgxRjgK9axsQuUa/oKMx5DEY8oXpKJfk61rT5iY3aRlgU6QJtUcxU5OAymdhCvWvhYcd9FKmO5eQoX8m9VGJXg==", "dev": true, "bin": { "marked": "bin/marked.js" }, "engines": { - "node": ">= 16" + "node": ">= 18" } }, "node_modules/marked-terminal": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-6.1.0.tgz", - "integrity": "sha512-QaCSF6NV82oo6K0szEnmc65ooDeW0T/Adcyf0fcW+Hto2GT1VADFg8dn1zaeHqzj65fqDH1hMNChGNRaC/lbkA==", + "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.0", + "node-emoji": "^2.1.3", "supports-hyperlinks": "^3.0.0" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "marked": ">=1 <11" + "marked": ">=1 <12" } }, "node_modules/meow": { @@ -2338,15 +2701,18 @@ } }, "node_modules/mime": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", - "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.1.tgz", + "integrity": "sha512-5lZ5tyrIfliMXzFtkYyekWbtRXObT9OWa8IwQ5uxTBDHucNNwniRqo0yInflj+iYi5CBa6qxadGzGarDfuEOxA==", "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], "bin": { - "mime": "cli.js" + "mime": "bin/cli.js" }, "engines": { - "node": ">=10.0.0" + "node": ">=16" } }, "node_modules/mimic-fn": { @@ -2428,9 +2794,9 @@ } }, "node_modules/npm": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.4.tgz", - "integrity": "sha512-umEuYneVEYO9KoEEI8n2sSGmNQeqco/3BSeacRlqIkCzw4E7XGtYSWMeJobxzr6hZ2n9cM+u5TsMTcC5bAgoWA==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.4.0.tgz", + "integrity": "sha512-RS7Mx0OVfXlOcQLRePuDIYdFCVBPCNapWHplDK+mh7GDdP/Tvor4ocuybRRPSvfcRb2vjRJt1fHCqw3cr8qACQ==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", @@ -2494,7 +2860,6 @@ "semver", "spdx-expression-parse", "ssri", - "strip-ansi", "supports-color", "tar", "text-table", @@ -2512,12 +2877,12 @@ "@npmcli/fs": "^3.1.0", "@npmcli/map-workspaces": "^3.0.4", "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.2", - "@sigstore/tuf": "^2.2.0", + "@npmcli/promise-spawn": "^7.0.1", + "@npmcli/run-script": "^7.0.4", + "@sigstore/tuf": "^2.3.0", "abbrev": "^2.0.0", "archy": "~1.0.0", - "cacache": "^18.0.0", + "cacache": "^18.0.2", "chalk": "^5.3.0", "ci-info": "^4.0.0", "cli-columns": "^4.0.0", @@ -2531,7 +2896,7 @@ "ini": "^4.1.1", "init-package-json": "^6.0.0", "is-cidr": "^5.0.3", - "json-parse-even-better-errors": "^3.0.0", + "json-parse-even-better-errors": "^3.0.1", "libnpmaccess": "^8.0.1", "libnpmdiff": "^6.0.3", "libnpmexec": "^7.0.4", @@ -2560,7 +2925,7 @@ "npm-user-validate": "^2.0.0", "npmlog": "^7.0.1", "p-map": "^4.0.0", - "pacote": "^17.0.4", + "pacote": "^17.0.6", "parse-conflict-json": "^3.0.1", "proc-log": "^3.0.0", "qrcode-terminal": "^0.12.0", @@ -2568,7 +2933,6 @@ "semver": "^7.5.4", "spdx-expression-parse": "^3.0.1", "ssri": "^10.0.5", - "strip-ansi": "^7.1.0", "supports-color": "^9.4.0", "tar": "^6.2.0", "text-table": "~0.2.0", @@ -2625,6 +2989,18 @@ "node": ">=12" } }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "dev": true, @@ -2648,6 +3024,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", "dev": true, @@ -2671,7 +3062,7 @@ } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "7.2.1", + "version": "7.3.1", "dev": true, "inBundle": true, "license": "ISC", @@ -2703,7 +3094,7 @@ "parse-conflict-json": "^3.0.0", "proc-log": "^3.0.0", "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.2", + "promise-call-limit": "^3.0.1", "read-package-json-fast": "^3.0.2", "semver": "^7.3.7", "ssri": "^10.0.5", @@ -2718,7 +3109,7 @@ } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "8.0.2", + "version": "8.1.0", "dev": true, "inBundle": true, "license": "ISC", @@ -2776,7 +3167,7 @@ } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "5.0.3", + "version": "5.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -2877,7 +3268,7 @@ } }, "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "7.0.0", + "version": "7.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -2901,15 +3292,15 @@ } }, "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "7.0.2", + "version": "7.0.4", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", "@npmcli/promise-spawn": "^7.0.0", "node-gyp": "^10.0.0", - "read-package-json-fast": "^3.0.0", "which": "^4.0.0" }, "engines": { @@ -2927,7 +3318,7 @@ } }, "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "2.1.0", + "version": "2.1.1", "dev": true, "inBundle": true, "license": "Apache-2.0", @@ -2938,6 +3329,15 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/npm/node_modules/@sigstore/core": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { "version": "0.2.1", "dev": true, @@ -2948,12 +3348,13 @@ } }, "node_modules/npm/node_modules/@sigstore/sign": { - "version": "2.2.0", + "version": "2.2.1", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.0", + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", "@sigstore/protobuf-specs": "^0.2.1", "make-fetch-happen": "^13.0.0" }, @@ -2962,13 +3363,27 @@ } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "2.2.0", + "version": "2.3.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "0.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -3005,18 +3420,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/abort-controller": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, "node_modules/npm/node_modules/agent-base": { "version": "7.1.0", "dev": true, @@ -3043,15 +3446,12 @@ } }, "node_modules/npm/node_modules/ansi-regex": { - "version": "6.0.1", + "version": "5.0.1", "dev": true, "inBundle": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">=8" } }, "node_modules/npm/node_modules/ansi-styles": { @@ -3079,41 +3479,17 @@ "license": "MIT" }, "node_modules/npm/node_modules/are-we-there-yet": { - "version": "4.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^4.1.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/base64-js": { - "version": "1.5.1", + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], "inBundle": true, "license": "MIT" }, @@ -3150,30 +3526,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/npm/node_modules/buffer": { - "version": "6.0.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/npm/node_modules/builtins": { "version": "5.0.1", "dev": true, @@ -3184,7 +3536,7 @@ } }, "node_modules/npm/node_modules/cacache": { - "version": "18.0.0", + "version": "18.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -3194,7 +3546,7 @@ "glob": "^10.2.2", "lru-cache": "^10.0.1", "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", @@ -3276,27 +3628,6 @@ "node": ">= 10" } }, - "node_modules/npm/node_modules/cli-columns/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cli-columns/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/cli-table3": { "version": "0.6.3", "dev": true, @@ -3370,27 +3701,6 @@ "node": ">=8.0.0" } }, - "node_modules/npm/node_modules/columnify/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/columnify/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", "dev": true, @@ -3479,12 +3789,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm/node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/diff": { "version": "5.1.0", "dev": true, @@ -3531,24 +3835,6 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/event-target-shim": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/events": { - "version": "3.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/npm/node_modules/exponential-backoff": { "version": "3.1.1", "dev": true, @@ -3620,27 +3906,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/gauge/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/gauge/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/glob": { "version": "10.3.10", "dev": true, @@ -3744,28 +4009,8 @@ "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/ieee754": { - "version": "1.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "BSD-3-Clause" - }, "node_modules/npm/node_modules/ignore-walk": { - "version": "6.0.3", + "version": "6.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -3903,7 +4148,7 @@ } }, "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "MIT", @@ -3942,7 +4187,7 @@ "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { - "version": "8.0.1", + "version": "8.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -3955,7 +4200,7 @@ } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "6.0.3", + "version": "6.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -3975,7 +4220,7 @@ } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "7.0.4", + "version": "7.0.7", "dev": true, "inBundle": true, "license": "ISC", @@ -3997,7 +4242,7 @@ } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "5.0.1", + "version": "5.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -4009,7 +4254,7 @@ } }, "node_modules/npm/node_modules/libnpmhook": { - "version": "10.0.0", + "version": "10.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -4022,7 +4267,7 @@ } }, "node_modules/npm/node_modules/libnpmorg": { - "version": "6.0.1", + "version": "6.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -4035,7 +4280,7 @@ } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "6.0.3", + "version": "6.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -4050,7 +4295,7 @@ } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "9.0.2", + "version": "9.0.4", "dev": true, "inBundle": true, "license": "ISC", @@ -4061,7 +4306,7 @@ "npm-registry-fetch": "^16.0.0", "proc-log": "^3.0.0", "semver": "^7.3.7", - "sigstore": "^2.1.0", + "sigstore": "^2.2.0", "ssri": "^10.0.5" }, "engines": { @@ -4069,7 +4314,7 @@ } }, "node_modules/npm/node_modules/libnpmsearch": { - "version": "7.0.0", + "version": "7.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -4081,7 +4326,7 @@ } }, "node_modules/npm/node_modules/libnpmteam": { - "version": "6.0.0", + "version": "6.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -4094,7 +4339,7 @@ } }, "node_modules/npm/node_modules/libnpmversion": { - "version": "5.0.1", + "version": "5.0.2", "dev": true, "inBundle": true, "license": "ISC", @@ -4110,13 +4355,10 @@ } }, "node_modules/npm/node_modules/lru-cache": { - "version": "10.0.2", + "version": "10.1.0", "dev": true, "inBundle": true, "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, "engines": { "node": "14 || >=16.14" } @@ -4168,27 +4410,15 @@ } }, "node_modules/npm/node_modules/minipass-collect": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", + "version": "2.0.1", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/npm/node_modules/minipass-fetch": { @@ -4475,12 +4705,12 @@ } }, "node_modules/npm/node_modules/npm-packlist": { - "version": "8.0.0", + "version": "8.0.2", "dev": true, "inBundle": true, "license": "ISC", "dependencies": { - "ignore-walk": "^6.0.0" + "ignore-walk": "^6.0.4" }, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -4572,7 +4802,7 @@ } }, "node_modules/npm/node_modules/pacote": { - "version": "17.0.4", + "version": "17.0.6", "dev": true, "inBundle": true, "license": "ISC", @@ -4592,7 +4822,7 @@ "promise-retry": "^2.0.1", "read-package-json": "^7.0.0", "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", + "sigstore": "^2.2.0", "ssri": "^10.0.0", "tar": "^6.1.11" }, @@ -4643,7 +4873,7 @@ } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.0.13", + "version": "6.0.15", "dev": true, "inBundle": true, "license": "MIT", @@ -4664,15 +4894,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/process": { - "version": "0.11.10", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6.0" - } - }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", "dev": true, @@ -4683,7 +4904,7 @@ } }, "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.2", + "version": "3.0.1", "dev": true, "inBundle": true, "license": "ISC", @@ -4779,22 +5000,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/readable-stream": { - "version": "4.4.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10", - "string_decoder": "^1.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, "node_modules/npm/node_modules/retry": { "version": "0.12.0", "dev": true, @@ -4804,26 +5009,6 @@ "node": ">= 4" } }, - "node_modules/npm/node_modules/safe-buffer": { - "version": "5.2.1", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/safer-buffer": { "version": "2.1.2", "dev": true, @@ -4898,15 +5083,17 @@ } }, "node_modules/npm/node_modules/sigstore": { - "version": "2.1.0", + "version": "2.2.0", "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.0", + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.1.0", - "@sigstore/tuf": "^2.1.0" + "@sigstore/sign": "^2.2.1", + "@sigstore/tuf": "^2.3.0", + "@sigstore/verify": "^0.1.0" }, "engines": { "node": "^16.14.0 || >=18.0.0" @@ -4977,116 +5164,62 @@ } }, "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.16", - "dev": true, - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/ssri": { - "version": "10.0.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/string_decoder": { - "version": "1.3.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", + "version": "3.0.16", "dev": true, "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } + "license": "CC0-1.0" }, - "node_modules/npm/node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", + "node_modules/npm/node_modules/ssri": { + "version": "10.0.5", "dev": true, "inBundle": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", "dev": true, "inBundle": true, "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { "node": ">=8" } }, - "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, "node_modules/npm/node_modules/strip-ansi": { - "version": "7.1.0", + "version": "6.0.1", "dev": true, "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=8" } }, "node_modules/npm/node_modules/strip-ansi-cjs": { @@ -5102,15 +5235,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/supports-color": { "version": "9.4.0", "dev": true, @@ -5195,7 +5319,7 @@ } }, "node_modules/npm/node_modules/tuf-js": { - "version": "2.1.0", + "version": "2.2.0", "dev": true, "inBundle": true, "license": "MIT", @@ -5343,15 +5467,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, @@ -5367,16 +5482,16 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { "version": "6.0.1", "dev": true, "inBundle": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { @@ -5402,6 +5517,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/npm/node_modules/write-file-atomic": { "version": "5.0.1", "dev": true, @@ -5458,15 +5588,15 @@ } }, "node_modules/p-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-3.0.0.tgz", - "integrity": "sha512-QtoWLjXAW++uTX67HZQz1dbTpqBfiidsB6VtQUC9iR85S120+s0T5sO6s+B5MLzFcZkrEd/DGMmCjR+f2Qpxwg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-4.1.0.tgz", + "integrity": "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==", "dev": true, "dependencies": { - "p-map": "^5.1.0" + "p-map": "^7.0.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5481,59 +5611,37 @@ "node": ">=8" } }, - "node_modules/p-map": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", - "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", - "dev": true, - "dependencies": { - "aggregate-error": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map/node_modules/aggregate-error": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", - "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "dependencies": { - "clean-stack": "^4.0.0", - "indent-string": "^5.0.0" + "p-try": "^1.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/p-map/node_modules/clean-stack": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", - "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", "dev": true, "dependencies": { - "escape-string-regexp": "5.0.0" + "p-limit": "^1.1.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/p-map/node_modules/indent-string": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", - "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "node_modules/p-map": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.1.tgz", + "integrity": "sha512-2wnaR0XL/FDOj+TgpDuRb2KTjLnu3Fma6b1ZUwGY7LcqenMcvP/YFpjpbPKY6WVGsbuJZRuoUz8iPrt8ORnAFw==", "dev": true, "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5548,6 +5656,15 @@ "node": ">=8" } }, + "node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5584,6 +5701,15 @@ "integrity": "sha512-u7p959wLfGAhJpSDJVYXoyMCXWYwHia78HhRBWqk7AIbxdmlrfdp5wX0l3xv/iTSH5HvhN9K7o26hwwpgS5Nmw==", "dev": true }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -5636,73 +5762,6 @@ "node": ">=4" } }, - "node_modules/pkg-conf/node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", - "dev": true, - "dependencies": { - "locate-path": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", - "dev": true, - "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", - "dev": true, - "dependencies": { - "p-limit": "^1.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/pkg-conf/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5710,15 +5769,15 @@ "dev": true }, "node_modules/promisified-properties": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/promisified-properties/-/promisified-properties-2.0.27.tgz", - "integrity": "sha512-fmx256M3b0QcHnqOj+Ok127LoYpmnYRf7g2OyLl7qD7Z0fzNbIZhHHIPKyvegbA29iAPP5BVWv7BJ/y2cMHHjA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/promisified-properties/-/promisified-properties-3.0.0.tgz", + "integrity": "sha512-ARteuBuUpPg/+spsMhcKHvdtOW/q8btyyVYYxxegGgx+7u9ix9at8DjP2KM2t8+4SuI8wBLt+3X876FMQx91yQ==", "dev": true, "dependencies": { "parsimmon": "^1.13.0" }, "engines": { - "node": ">=14.16", + "node": ">=18", "npm": ">=7.12" } }, @@ -5801,9 +5860,9 @@ } }, "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", - "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz", + "integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==", "dev": true, "engines": { "node": ">=16" @@ -5812,24 +5871,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", - "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/read-pkg/node_modules/parse-json": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.0.1.tgz", - "integrity": "sha512-soKUg/q/8bcfuF3+plsbYldE74cVEVEPSC1BUPIGTaX1byXdz6Fo+CVYBdH0jj/5xWsFrNRksl11QkBgHqPQeQ==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.1.0.tgz", + "integrity": "sha512-rum1bPifK5SSar35Z6EKZuYPJx85pkNaFrxBK3mwdfSJ1/WKbYrjoW/zTPSjRRamfmVX1ACBIdFAO0VRErW/EA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.22.13", - "index-to-position": "^0.1.1", - "json-parse-even-better-errors": "^3.0.0", + "index-to-position": "^0.1.2", "type-fest": "^4.7.1" }, "engines": { @@ -5840,9 +5889,9 @@ } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.8.2.tgz", - "integrity": "sha512-mcvrCjixA5166hSrUoJgGb9gBQN4loMYyj9zxuMs/66ibHNEFd5JXMw37YVDx58L4/QID9jIzdTBB4mDwDJ6KQ==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.10.1.tgz", + "integrity": "sha512-7ZnJYTp6uc04uYRISWtiX3DSKB/fxNQT0B5o1OUeCqiQiwF+JC9+rJiZIDrPrNCLLuTqyQmh4VdQqh/ZOkv9MQ==", "dev": true, "engines": { "node": ">=16" @@ -5945,9 +5994,9 @@ "dev": true }, "node_modules/semantic-release": { - "version": "22.0.12", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-22.0.12.tgz", - "integrity": "sha512-0mhiCR/4sZb00RVFJIUlMuiBkW3NMpVIW2Gse7noqEMoFGkvfPPAImEQbkBV8xga4KOPP4FdTRYuLLy32R1fPw==", + "version": "23.0.0", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-23.0.0.tgz", + "integrity": "sha512-Jz7jEWO2igTtske112gC4PPE2whCMVrsgxUPG3/SZI7VE357suIUZFlJd1Yu0g2I6RPc2HxNEfUg7KhmDTjwqg==", "dev": true, "dependencies": { "@semantic-release/commit-analyzer": "^11.0.0", @@ -5956,9 +6005,9 @@ "@semantic-release/npm": "^11.0.0", "@semantic-release/release-notes-generator": "^12.0.0", "aggregate-error": "^5.0.0", - "cosmiconfig": "^8.0.0", + "cosmiconfig": "^9.0.0", "debug": "^4.0.0", - "env-ci": "^10.0.0", + "env-ci": "^11.0.0", "execa": "^8.0.0", "figures": "^6.0.0", "find-versions": "^5.1.0", @@ -5968,7 +6017,7 @@ "hosted-git-info": "^7.0.0", "import-from-esm": "^1.3.1", "lodash-es": "^4.17.21", - "marked": "^9.0.0", + "marked": "^11.0.0", "marked-terminal": "^6.0.0", "micromatch": "^4.0.2", "p-each-series": "^3.0.0", @@ -5984,7 +6033,7 @@ "semantic-release": "bin/semantic-release.js" }, "engines": { - "node": "^18.17 || >=20.6.1" + "node": ">=20.8.1" } }, "node_modules/semantic-release/node_modules/@semantic-release/error": { @@ -6027,6 +6076,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/semantic-release/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/semantic-release/node_modules/execa": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", @@ -6108,9 +6169,9 @@ } }, "node_modules/semantic-release/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", + "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -6321,15 +6382,6 @@ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "dev": true }, - "node_modules/signale/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/signale/node_modules/figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -6413,9 +6465,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.4.0.tgz", + "integrity": "sha512-hcjppoJ68fhxA/cjbN4T8N6uCUejN8yFw69ttpqtBeCbF3u13n7mb31NB9jKwGTTWWnt9IbRA/mf1FprYS8wfw==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -6609,6 +6661,16 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -6622,10 +6684,13 @@ } }, "node_modules/traverse": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz", - "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==", + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", "dev": true, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6698,9 +6763,9 @@ "dev": true }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "engines": { "node": ">= 10.0.0" @@ -6800,9 +6865,9 @@ "dev": true }, "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { "cliui": "^8.0.1", @@ -6817,7 +6882,7 @@ "node": ">=12" } }, - "node_modules/yargs/node_modules/yargs-parser": { + "node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", diff --git a/package.json b/package.json index f9c0647e10..3101070000 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "@saithodev/semantic-release-backmerge": "^4.0.1", "@semantic-release/changelog": "^6.0.3", "@semantic-release/git": "^10.0.1", - "gradle-semantic-release-plugin": "^1.8.0", - "semantic-release": "^22.0.12" + "gradle-semantic-release-plugin": "^1.9.1", + "semantic-release": "^23.0.0" } } diff --git a/patches.json b/patches.json index 2bb35ffd17..f98e7072f6 100644 --- a/patches.json +++ b/patches.json @@ -1 +1 @@ -[{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.awedea.nyx","versions":["2.2.7"]}],"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":"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":"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":"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":"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":"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":"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":"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":"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 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":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","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 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":"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":"Remove broadcasts restriction","description":"Enables starting/stopping NetGuard via broadcasts.","compatiblePackages":[{"name":"eu.faircode.netguard","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":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","versions":null}],"use":true,"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 Wi-Fi connection","description":"Spoofs an existing Wi-Fi connection.","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":"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":"Change package name","description":"Appends \".revanced\" to the package name by default.","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":"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":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"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":"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":"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":"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":"Remove root detection","description":"Removes the check for root permissions and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.oe.app","versions":["3.0.2"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof signature","description":"Spoofs the signature of the app.","compatiblePackages":[{"name":"at.gv.oe.app","versions":["3.0.2"]}],"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":"Remove debugging detection","description":"Removes the USB and wireless debugging checks.","compatiblePackages":[{"name":"com.scb.phone","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","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":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","versions":null}],"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":"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":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","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":"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 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":"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":null,"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}],"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":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","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":"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 ads","description":"Hides ads.","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":"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":"Theme","description":"Applies a custom theme.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"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 player popup panels","description":"Disables 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable resuming Shorts on startup","description":"Disables resuming the Shorts player on app startup if a Short was last opened.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Enables 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide autoplay button","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide video action buttons","description":"Adds options to hide action buttons under a 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Navigation buttons","description":"Adds options to hide or change navigation buttons.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide player buttons","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide cast button","description":"Hides the cast button in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof app version","description":"Tricks 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable auto captions","description":"Disable forced 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom branding","description":"Changes the app name and icon to your choice (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":"Premium heading","description":"Show or hide the premium heading.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[{"key":"usePremiumHeading","default":true,"values":null,"title":"Use premium heading","description":"Whether to use the premium heading.","required":true}]},{"name":"Alternative thumbnails","description":"Adds options to replace video thumbnails with still image captures of 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable tablet layout","description":"Spoofs 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":"Return YouTube Dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Change start page","description":"Changes the start page of the app.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Custom player overlay opacity","description":"Change the opacity of the 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 background from 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.41","18.45.43"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Hides info cards in 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide floating microphone button","description":"Hides the floating microphone button which appears in search.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide album cards","description":"Hides the album cards below the artist 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide crowdfunding box","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Hides player flyout menu items.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide breaking news shelf","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Hides the 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable fullscreen ambient mode","description":"Disables 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide layout components","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Hides components from 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide filter bar","description":"Hides the filter bar in 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide \u0027Load more\u0027 button","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable rolling number animations","description":"Disables 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Hides 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Hides timestamp in 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable suggested video end screen","description":"Disables the suggested video end screen at the end of a video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Wide searchbar","description":"Replaces 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old seekbar thumbnails","description":"Restores the old seekbar thumbnails that appear above the seekbar 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Integrates SponsorBlock, which can skip undesired video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove viewer discretion dialog","description":"Removes the dialog that appears when you try to watch 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":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"External downloads","description":"Adds support to download and save YouTube videos using an external app.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Copy video url","description":"Adds buttons in player to copy video links.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Seekbar tapping","description":"Enables 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable precise seeking gesture","description":"Disables the gesture that is used to seek precisely 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable slide to seek","description":"Enable slide to seek instead of playing at 2x speed when pressing and holding in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds the ability to remember the last video quality selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"HDR auto brightness","description":"Makes 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Restore old video quality menu","description":"Restores the old video quality with advanced video quality 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds custom playback speeds and ability to remember the last playback speed selected.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Video ads","description":"Removes 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Enables minimized and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable debugging","description":"Adds debugging options.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Open links externally","description":"Open links outside of the app directly in your 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.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Bypass URL redirects","description":"Bypass URL redirects and open the original URL directly.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Always autorepeat","description":"Always repeats the playing video again.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove tracking query parameter","description":"Remove the tracking query parameter from links you share.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Client spoof","description":"Spoofs the client to allow playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"GmsCore support","description":"Allows 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.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"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":"Spoofs the device dimensions in order to unlock higher video qualities that may not be available on your device.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.38.44","18.43.45","18.44.41","18.45.41","18.45.43"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Announcements","description":"Shows ReVanced announcements on startup.","compatiblePackages":[{"name":"com.google.android.youtube","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable zoom haptics","description":"Disables haptics when zooming.","compatiblePackages":[{"name":"com.google.android.youtube","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":"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":"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":"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":"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":"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":"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":"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.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 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":"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":"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":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.wakdev.apps.nfctools.se","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":"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":"Playback speed","description":"Enables the playback speed option for all 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":"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":"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":"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":"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":"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":"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":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","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 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 plus","description":null,"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":"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":"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 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":"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":"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 and unlocked bootloader.","compatiblePackages":[{"name":"at.gv.bka.serviceportal","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":"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":[]}] \ No newline at end of file +[{"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":"Remove broadcasts restriction","description":"Enables starting/stopping NetGuard via broadcasts.","compatiblePackages":[{"name":"eu.faircode.netguard","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":"Disable dashboard ads","description":"Disables ads in the dashboard.","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 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 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":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}],"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":"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":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":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":["4.29"]}],"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":"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":"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":"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":"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":"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.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":"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":"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 ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"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":"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":"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 pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":null}],"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":"org.totschnig.myexpenses","versions":["3.4.9"]}],"use":true,"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":"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":"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":"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":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Spoof Wi-Fi connection","description":"Spoofs an existing Wi-Fi connection.","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":"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":"com.ithebk.expensemanager","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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"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":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","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":"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":"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":"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 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":"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":"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":"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":"Hide premium navbar","description":"Removes the premium tab from the navbar.","compatiblePackages":[{"name":"com.spotify.music","versions":null}],"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":"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":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","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 ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","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":"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":"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":"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":"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":"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":"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":"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":"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":"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"]}],"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"]}],"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"]}],"use":true,"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"]}],"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"]}],"use":false,"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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":"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"]}],"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"]}],"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"]}],"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":"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"]}],"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":"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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":"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"]}],"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":"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"]}],"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":"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"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"]}],"use":false,"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 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.\n The 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\n These folders must contain the following files:\n\n - yt_wordmark_header_light.png\n- yt_wordmark_header_dark.png","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 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":"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"]}],"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"]}],"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"]}],"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"]}],"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 debugging detection","description":"Removes the USB and wireless debugging checks.","compatiblePackages":[{"name":"com.scb.phone","versions":null}],"use":false,"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":"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":"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":"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":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","versions":null}],"use":true,"requiresIntegrations":false,"options":[]}] \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt b/src/main/kotlin/app/revanced/meta/IPatchesFileGenerator.kt similarity index 78% rename from src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt rename to src/main/kotlin/app/revanced/meta/IPatchesFileGenerator.kt index 61d8e85dae..49d46e5141 100644 --- a/src/main/kotlin/app/revanced/meta/PatchesFileGenerator.kt +++ b/src/main/kotlin/app/revanced/meta/IPatchesFileGenerator.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.PatchBundleLoader import app.revanced.patcher.PatchSet import java.io.File -internal interface PatchesFileGenerator { +internal interface IPatchesFileGenerator { fun generate(patches: PatchSet) private companion object { @@ -14,7 +14,7 @@ internal interface PatchesFileGenerator { ).also { loader -> if (loader.isEmpty()) throw IllegalStateException("No patches found") }.let { bundle -> - arrayOf(JsonGenerator()).forEach { generator -> generator.generate(bundle) } + arrayOf(JsonPatchesFileGenerator()).forEach { generator -> generator.generate(bundle) } } } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/meta/JsonGenerator.kt b/src/main/kotlin/app/revanced/meta/JsonPatchesFileGenerator.kt similarity index 95% rename from src/main/kotlin/app/revanced/meta/JsonGenerator.kt rename to src/main/kotlin/app/revanced/meta/JsonPatchesFileGenerator.kt index 651297e2fd..6755706c68 100644 --- a/src/main/kotlin/app/revanced/meta/JsonGenerator.kt +++ b/src/main/kotlin/app/revanced/meta/JsonPatchesFileGenerator.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.patch.Patch import com.google.gson.GsonBuilder import java.io.File -internal class JsonGenerator : PatchesFileGenerator { +internal class JsonPatchesFileGenerator : IPatchesFileGenerator { override fun generate(patches: PatchSet) = patches.map { JsonPatch( it.name!!, diff --git a/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch.kt b/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch.kt index c25f803093..3f79c29e9f 100644 --- a/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/connectivity/wifi/spoof/SpoofWifiPatch.kt @@ -2,7 +2,7 @@ package app.revanced.patches.all.connectivity.wifi.spoof import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch +import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch import app.revanced.patches.all.misc.transformation.IMethodCall import app.revanced.patches.all.misc.transformation.Instruction35cInfo import app.revanced.patches.all.misc.transformation.filterMapInstruction35c @@ -17,8 +17,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction requiresIntegrations = true ) @Suppress("unused") -object SpoofWifiPatch : AbstractTransformInstructionsPatch() { - private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/all/connectivity/wifi/spoof/SpoofWifiPatch" +object SpoofWifiPatch : BaseTransformInstructionsPatch() { + private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = "Lapp/revanced/integrations/all/connectivity/wifi/spoof/SpoofWifiPatch" private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;" override fun filterMap( 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 4097859769..ea847c4d70 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 @@ -10,7 +10,7 @@ import java.io.Closeable @Patch( name = "Change package name", - description = "Appends \".revanced\" to the package name by default.", + description = "Appends \".revanced\" to the package name by default. Changing the package name of the app can lead to unexpected issues.", use = false ) @Suppress("unused") @@ -41,22 +41,22 @@ object ChangePackageNamePatch : ResourcePatch(), Closeable { * @throws PatchOptionException.ValueValidationException If the package name is invalid. */ fun setOrGetFallbackPackageName(fallbackPackageName: String): String { - val packageName = this.packageNameOption.value!! + val packageName = packageNameOption.value!! - return if (packageName == this.packageNameOption.default) - fallbackPackageName.also { this.packageNameOption.value = it } + return if (packageName == packageNameOption.default) + fallbackPackageName.also { packageNameOption.value = it } else packageName } override fun close() = context.xmlEditor["AndroidManifest.xml"].use { editor -> - val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element - val originalPackageName = manifest.getAttribute("package") - - var replacementPackageName = this.packageNameOption.value - if (replacementPackageName == this.packageNameOption.default) - replacementPackageName = "$originalPackageName.revanced" + val replacementPackageName = packageNameOption.value - manifest.setAttribute("package", replacementPackageName) + val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element + manifest.setAttribute( + "package", + if (replacementPackageName != packageNameOption.default) replacementPackageName + else "${manifest.getAttribute("package")}.revanced" + ) } -} \ No newline at end of file +} 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 new file mode 100644 index 0000000000..bb72c077df --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/all/misc/resources/AddResourcesPatch.kt @@ -0,0 +1,277 @@ +package app.revanced.patches.all.misc.resources + +import app.revanced.patcher.PatchClass +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.patches.all.misc.resources.AddResourcesPatch.resources +import app.revanced.util.* +import app.revanced.util.resource.ArrayResource +import app.revanced.util.resource.BaseResource +import app.revanced.util.resource.StringResource +import org.w3c.dom.Node +import java.io.Closeable +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`. + */ +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. + */ +private typealias Resources = MutableMap + +/** + * The value of a resource. + * For example, `values` or `values-de`. + */ +private typealias Value = String + +@Patch(description = "Add resources such as strings or arrays to the app.") +object AddResourcesPatch : ResourcePatch(), MutableMap> by mutableMapOf(), Closeable { + private lateinit var context: ResourceContext + + /** + * A map of all resources associated by their value staged by [execute]. + */ + private lateinit var resources: Map + + /* + The strategy of this patch is to stage resources present in `/resources/addresources`. + These resources are organized by their respective value and patch. + + On AddResourcesPatch#execute, all resources are staged in a temporary map. + After that, other patches that depend on AddResourcesPatch can call + AddResourcesPatch#invoke(PatchClass) to stage resources belonging to that patch + from the temporary map to AddResourcesPatch. + + After all patches that depend on AddResourcesPatch have been executed, + AddResourcesPatch#close is finally called to add all staged resources to the app. + */ + override fun execute(context: ResourceContext) { + this.context = context + + 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.xmlEditor[stream].use { + it.file.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(patchId, ::mutableSetOf).apply { + patch.forEachChildElement { resourceNode -> + val resource = transform(resourceNode) + + add(resource) + } + } + } + } + } + } + } + } + } + + // 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) + } + } + } + + /** + * Adds a [BaseResource] to the map using [MutableMap.getOrPut]. + * + * @param value The value of the resource. For example, `values` or `values-de`. + * @param resource The resource to add. + * + * @return True if the resource was added, false if it already existed. + */ + operator fun invoke(value: Value, resource: BaseResource) = + getOrPut(value, ::mutableSetOf).add(resource) + + /** + * Adds a list of [BaseResource]s to the map using [MutableMap.getOrPut]. + * + * @param value The value of the resource. For example, `values` or `values-de`. + * @param resources The resources to add. + * + * @return True if the resources were added, false if they already existed. + */ + operator fun invoke(value: Value, resources: Iterable) = + getOrPut(value, ::mutableSetOf).addAll(resources) + + /** + * Adds a [StringResource]. + * + * @param name The name of the string resource. + * @param value The value of the string resource. + * @param formatted Whether the string resource is formatted. Defaults to `true`. + * @param resourceValue The value of the resource. For example, `values` or `values-de`. + * + * @return True if the resource was added, false if it already existed. + */ + operator fun invoke( + name: String, + value: String, + formatted: Boolean = true, + resourceValue: Value = "values", + ) = invoke(resourceValue, StringResource(name, value, formatted)) + + /** + * Adds an [ArrayResource]. + * + * @param name The name of the array resource. + * @param items The items of the array resource. + * + * @return True if the resource was added, false if it already existed. + */ + operator fun invoke( + name: String, + items: List + ) = invoke("values", ArrayResource(name, items)) + + + /** + * Puts all resources of any [Value] staged in [resources] for the given [PatchClass] to [AddResourcesPatch]. + * + * @param patch The class of the patch to add resources for. + * @param parseIds A function that parses the [AppId] and [PatchId] from the given [PatchClass]. + * This is used to access the resources in [resources] to stage them in [AddResourcesPatch]. + * The default implementation assumes that the [PatchClass] qualified name has the following format: + * `....`. + * + * @return True if any resources were added, false if none were added. + * + * @see AddResourcesPatch.close + */ + operator fun invoke( + patch: PatchClass, + parseIds: PatchClass.() -> Pair = { + val qualifiedName = qualifiedName ?: throw PatchException("Patch qualified name is null") + + // This requires qualifiedName to have the following format: + // `....` + with(qualifiedName.split(".")) { + if (size < 5) throw PatchException("Patch qualified name has invalid format") + + val appId = this[3] + val patchId = subList(4, size).joinToString(".") + + appId to patchId + } + } + ): Boolean { + val (appId, patchId) = patch.parseIds() + + var result = false + + // Stage resources for the given patch to AddResourcesPatch associated with their value. + resources.forEach { (value, resources) -> + resources[appId]?.get(patchId)?.let { patchResources -> + if (invoke(value, patchResources)) result = true + } + } + + return result + } + + /** + * Adds all resources staged in [AddResourcesPatch] to the app. + * This is called after all patches that depend on [AddResourcesPatch] have been executed. + */ + override fun close() { + operator fun MutableMap>.invoke( + value: Value, + 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 + // 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() + } + + context.xmlEditor[targetFile.path].let { editor -> + // 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") + } + }.let { (_, targetNode) -> + targetNode.addResource(resource) { invoke(value, it) } + } + } + + forEach { (value, resources) -> + // 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. + // 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>() + + resources.forEach { resource -> resourceFileEditors(value, resource) } + + resourceFileEditors.values.forEach { (editor, _) -> editor.close() } + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt similarity index 96% rename from src/main/kotlin/app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch.kt rename to src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt index 71699f1983..68e8a68bac 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/transformation/AbstractTransformInstructionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/transformation/BaseTransformInstructionsPatch.kt @@ -9,8 +9,7 @@ import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @Suppress("MemberVisibilityCanBePrivate") -abstract class AbstractTransformInstructionsPatch : BytecodePatch() { - +abstract class BaseTransformInstructionsPatch : BytecodePatch() { abstract fun filterMap( classDef: ClassDef, method: Method, diff --git a/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch.kt b/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch.kt index 4815f52320..b3afc3d6eb 100644 --- a/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/screencapture/removerestriction/RemoveCaptureRestrictionPatch.kt @@ -2,7 +2,7 @@ package app.revanced.patches.all.screencapture.removerestriction import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch +import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch import app.revanced.patches.all.misc.transformation.IMethodCall import app.revanced.patches.all.misc.transformation.Instruction35cInfo import app.revanced.patches.all.misc.transformation.filterMapInstruction35c @@ -18,9 +18,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction requiresIntegrations = true ) @Suppress("unused") -object RemoveCaptureRestrictionPatch : AbstractTransformInstructionsPatch() { +object RemoveCaptureRestrictionPatch : BaseTransformInstructionsPatch() { private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = - "Lapp/revanced/all/screencapture/removerestriction/RemoveScreencaptureRestrictionPatch" + "Lapp/revanced/integrations/all/screencapture/removerestriction/RemoveScreencaptureRestrictionPatch" private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;" // Information about method calls we want to replace enum class MethodCall( diff --git a/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch.kt b/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch.kt index 4f1db9ef58..0667ed0f57 100644 --- a/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch +import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch import app.revanced.patches.all.misc.transformation.IMethodCall import app.revanced.patches.all.misc.transformation.Instruction35cInfo import app.revanced.patches.all.misc.transformation.filterMapInstruction35c @@ -22,9 +22,9 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference requiresIntegrations = true, ) @Suppress("unused") -object RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch() { +object RemoveScreenshotRestrictionPatch : BaseTransformInstructionsPatch() { private const val INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX = - "Lapp/revanced/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch" + "Lapp/revanced/integrations/all/screenshot/removerestriction/RemoveScreenshotRestrictionPatch" private const val INTEGRATIONS_CLASS_DESCRIPTOR = "$INTEGRATIONS_CLASS_DESCRIPTOR_PREFIX;" override fun execute(context: BytecodeContext) { @@ -71,7 +71,7 @@ object RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch>() { +private class ModifyLayoutParamsFlags : BaseTransformInstructionsPatch>() { override fun filterMap( classDef: ClassDef, method: Method, diff --git a/src/main/kotlin/app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch.kt b/src/main/kotlin/app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch.kt index 068861b022..63afac86f2 100644 --- a/src/main/kotlin/app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch +import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @@ -23,7 +23,7 @@ import java.util.* use = false, ) @Suppress("unused") -object SpoofSimCountryPatch : AbstractTransformInstructionsPatch>() { +object SpoofSimCountryPatch : BaseTransformInstructionsPatch>() { private val countries = Locale.getISOCountries().associateBy { Locale("", it).displayCountry } private val networkCountryIso by isoCountryPatchOption( diff --git a/src/main/kotlin/app/revanced/patches/idaustria/detection/root/RootDetectionPatch.kt b/src/main/kotlin/app/revanced/patches/idaustria/detection/root/RootDetectionPatch.kt index 0c47f8dad7..2b720d3b21 100644 --- a/src/main/kotlin/app/revanced/patches/idaustria/detection/root/RootDetectionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/idaustria/detection/root/RootDetectionPatch.kt @@ -12,7 +12,7 @@ import app.revanced.util.returnEarly @Patch( name = "Remove root detection", description = "Removes the check for root permissions and unlocked bootloader.", - compatiblePackages = [CompatiblePackage("at.gv.oe.app", ["3.0.2"])] + compatiblePackages = [CompatiblePackage("at.gv.oe.app")] ) @Suppress("unused") object RootDetectionPatch : BytecodePatch( diff --git a/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/SpoofSignaturePatch.kt b/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/SpoofSignaturePatch.kt index a98c90bc5e..ae427b7441 100644 --- a/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/SpoofSignaturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/SpoofSignaturePatch.kt @@ -10,7 +10,7 @@ import app.revanced.patches.idaustria.detection.signature.fingerprints.SpoofSign @Patch( name = "Spoof signature", description = "Spoofs the signature of the app.", - compatiblePackages = [CompatiblePackage("at.gv.oe.app", ["3.0.2"])] + compatiblePackages = [CompatiblePackage("at.gv.oe.app")] ) @Suppress("unused") object SpoofSignaturePatch : BytecodePatch( diff --git a/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt index 9b2dcec9ea..5bb8e2a454 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportPatch.kt @@ -4,11 +4,13 @@ import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorOption import app.revanced.patches.music.misc.gms.fingerprints.* -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportPatch -import app.revanced.patches.youtube.misc.gms.fingerprints.CastContextFetchFingerprint +import app.revanced.patches.music.misc.integrations.fingerprints.ApplicationInitFingerprint +import app.revanced.patches.music.misc.integrations.IntegrationsPatch +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch +import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint @Suppress("unused") -object GmsCoreSupportPatch : AbstractGmsCoreSupportPatch( +object GmsCoreSupportPatch : BaseGmsCoreSupportPatch( fromPackageName = MUSIC_PACKAGE_NAME, toPackageName = REVANCED_MUSIC_PACKAGE_NAME, primeMethodFingerprint = PrimeMethodFingerprint, @@ -19,7 +21,9 @@ object GmsCoreSupportPatch : AbstractGmsCoreSupportPatch( CastDynamiteModuleV2Fingerprint, CastContextFetchFingerprint, ), - abstractGmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch, + mainActivityOnCreateFingerprint = ApplicationInitFingerprint, + integrationsPatchDependency = IntegrationsPatch::class, + gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch, compatiblePackages = setOf(CompatiblePackage("com.google.android.apps.youtube.music")), fingerprints = setOf( ServiceCheckFingerprint, diff --git a/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch.kt index 06c36bdef1..5daa421cab 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/gms/GmsCoreSupportResourcePatch.kt @@ -2,10 +2,10 @@ package app.revanced.patches.music.misc.gms import app.revanced.patches.music.misc.gms.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.gms.Constants.REVANCED_MUSIC_PACKAGE_NAME -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportResourcePatch +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch -object GmsCoreSupportResourcePatch : AbstractGmsCoreSupportResourcePatch( +object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch( fromPackageName = MUSIC_PACKAGE_NAME, toPackageName = REVANCED_MUSIC_PACKAGE_NAME, spoofedPackageSignature = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875" -) \ No newline at end of file +) 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 new file mode 100644 index 0000000000..06f45d7e97 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/integrations/IntegrationsPatch.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.music.misc.integrations + +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.music.misc.integrations.fingerprints.ApplicationInitFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch + +@Patch(requiresIntegrations = true) +object IntegrationsPatch : BaseIntegrationsPatch( + "Lapp/revanced/integrations/utils/ReVancedUtils;", + setOf( + ApplicationInitFingerprint, + ), +) diff --git a/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt new file mode 100644 index 0000000000..d825b4e8d3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/ApplicationInitFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.music.misc.integrations.fingerprints + +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object ApplicationInitFingerprint : IntegrationsFingerprint( + returnType = "V", + parameters = emptyList(), + opcodes = listOf( + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_STATIC, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_VIRTUAL + ), + strings = listOf("activity"), + customFingerprint = { methodDef, _ -> methodDef.name == "onCreate" }, +) diff --git a/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/HideAdsPatch.kt new file mode 100644 index 0000000000..855b486ba2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/HideAdsPatch.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.myfitnesspal.ads + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.myfitnesspal.ads.fingerprints.IsPremiumUseCaseImplFingerprint +import app.revanced.patches.myfitnesspal.ads.fingerprints.MainActivityNavigateToNativePremiumUpsellFingerprint +import app.revanced.util.exception + +@Patch( + name = "Hide ads", + description = "Hides most of the ads across the app.", + compatiblePackages = [CompatiblePackage("com.myfitnesspal.android")] +) +@Suppress("unused") +object HideAdsPatch : BytecodePatch( + setOf(IsPremiumUseCaseImplFingerprint, MainActivityNavigateToNativePremiumUpsellFingerprint) +) { + override fun execute(context: BytecodeContext) { + // Overwrite the premium status specifically for ads. + IsPremiumUseCaseImplFingerprint.result?.mutableMethod?.replaceInstructions( + 0, + """ + sget-object v0, Ljava/lang/Boolean;->TRUE:Ljava/lang/Boolean; + return-object v0 + """ + ) ?: throw IsPremiumUseCaseImplFingerprint.exception + + // Prevent the premium upsell dialog from showing when the main activity is launched. + // In other places that are premium-only the dialog will still show. + MainActivityNavigateToNativePremiumUpsellFingerprint.result?.mutableMethod?.replaceInstructions( + 0, + "return-void" + ) ?: throw MainActivityNavigateToNativePremiumUpsellFingerprint.exception + } +} diff --git a/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint.kt b/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint.kt new file mode 100644 index 0000000000..0f6e50e778 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/fingerprints/IsPremiumUseCaseImplFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.myfitnesspal.ads.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +object IsPremiumUseCaseImplFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC.value, + customFingerprint = { methodDef, classDef -> + classDef.type.endsWith("IsPremiumUseCaseImpl;") && methodDef.name == "doWork" + } +) diff --git a/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint.kt b/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint.kt new file mode 100644 index 0000000000..42cfb88c3c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/myfitnesspal/ads/fingerprints/MainActivityNavigateToNativePremiumUpsellFingerprint.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.myfitnesspal.ads.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +object MainActivityNavigateToNativePremiumUpsellFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + customFingerprint = { methodDef, classDef -> + classDef.type.endsWith("MainActivity;") && methodDef.name == "navigateToNativePremiumUpsell" + } +) diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt new file mode 100644 index 0000000000..1475559073 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/HideUpdatePopupPatch.kt @@ -0,0 +1,26 @@ +package app.revanced.patches.photomath.misc.annoyances + +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.photomath.detection.signature.SignatureDetectionPatch +import app.revanced.patches.photomath.misc.annoyances.fingerprints.HideUpdatePopupFingerprint +import app.revanced.util.exception + +@Patch( + name = "Hide update popup", + description = "Prevents the update popup from showing up.", + dependencies = [SignatureDetectionPatch::class], + compatiblePackages = [CompatiblePackage("com.microblink.photomath", ["8.32.0"])] +) +@Suppress("unused") +object HideUpdatePopupPatch : BytecodePatch( + setOf(HideUpdatePopupFingerprint) +) { + override fun execute(context: BytecodeContext) = HideUpdatePopupFingerprint.result?.mutableMethod?.addInstructions( + 2, // Insert after the null check. + "return-void" + ) ?: throw HideUpdatePopupFingerprint.exception +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/fingerprints/HideUpdatePopupFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/fingerprints/HideUpdatePopupFingerprint.kt new file mode 100644 index 0000000000..f57666b631 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/annoyances/fingerprints/HideUpdatePopupFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.photomath.misc.annoyances.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 HideUpdatePopupFingerprint : MethodFingerprint( + customFingerprint = { _, classDef -> + // The popup is shown only in the main activity + classDef.type == "Lcom/microblink/photomath/main/activity/MainActivity;" + }, + opcodes = listOf( + Opcode.CONST_HIGH16, + Opcode.INVOKE_VIRTUAL, // ViewPropertyAnimator.alpha(1.0f) + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_WIDE_16, + Opcode.INVOKE_VIRTUAL, // ViewPropertyAnimator.setDuration(1000L) + ), + accessFlags = AccessFlags.FINAL or AccessFlags.PUBLIC, + returnType = "V", +) diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/bookpoint/EnableBookpointPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt similarity index 81% rename from src/main/kotlin/app/revanced/patches/photomath/misc/bookpoint/EnableBookpointPatch.kt rename to src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt index f3dc575e03..6d12d0e296 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/bookpoint/EnableBookpointPatch.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/EnableBookpointPatch.kt @@ -1,11 +1,11 @@ -package app.revanced.patches.photomath.misc.bookpoint +package app.revanced.patches.photomath.misc.unlock.bookpoint import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.photomath.misc.bookpoint.fingerprints.IsBookpointEnabledFingerprint +import app.revanced.patches.photomath.misc.unlock.bookpoint.fingerprints.IsBookpointEnabledFingerprint @Patch(description = "Enables textbook access") internal object EnableBookpointPatch : BytecodePatch( diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/bookpoint/fingerprints/IsBookpointEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/fingerprints/IsBookpointEnabledFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/photomath/misc/bookpoint/fingerprints/IsBookpointEnabledFingerprint.kt rename to src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/fingerprints/IsBookpointEnabledFingerprint.kt index 0a60647a42..e5ae3c2daf 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/bookpoint/fingerprints/IsBookpointEnabledFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/bookpoint/fingerprints/IsBookpointEnabledFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.photomath.misc.bookpoint.fingerprints +package app.revanced.patches.photomath.misc.unlock.bookpoint.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/UnlockPlusPatch.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/UnlockPlusPatch.kt rename to src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt index 15ec53aba6..8895696cd8 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/UnlockPlusPatch.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/UnlockPlusPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.photomath.misc.unlockplus +package app.revanced.patches.photomath.misc.unlock.plus import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext @@ -7,8 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.photomath.detection.signature.SignatureDetectionPatch -import app.revanced.patches.photomath.misc.bookpoint.EnableBookpointPatch -import app.revanced.patches.photomath.misc.unlockplus.fingerprints.IsPlusUnlockedFingerprint +import app.revanced.patches.photomath.misc.unlock.bookpoint.EnableBookpointPatch +import app.revanced.patches.photomath.misc.unlock.plus.fingerprints.IsPlusUnlockedFingerprint @Patch( name = "Unlock plus", diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/fingerprints/IsPlusUnlockedFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt rename to src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/fingerprints/IsPlusUnlockedFingerprint.kt index 72db0e6bf5..2ab140b1d9 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlock/plus/fingerprints/IsPlusUnlockedFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.photomath.misc.unlockplus.fingerprints +package app.revanced.patches.photomath.misc.unlock.plus.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/HideAdsPatch.kt index 23a1c69ee6..02465c9054 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/general/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/ad/general/HideAdsPatch.kt @@ -26,7 +26,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Suppress("unused") object HideAdsPatch : BytecodePatch(setOf(AdPostFingerprint, NewAdPostFingerprint)) { private const val FILTER_METHOD_DESCRIPTOR = - "Lapp/revanced/reddit/patches/FilterPromotedLinksPatch;" + + "Lapp/revanced/integrations/reddit/patches/FilterPromotedLinksPatch;" + "->filterChildren(Ljava/lang/Iterable;)Ljava/util/List;" override fun execute(context: BytecodeContext) { diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/BaseSpoofClientPatch.kt similarity index 98% rename from src/main/kotlin/app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch.kt rename to src/main/kotlin/app/revanced/patches/reddit/customclients/BaseSpoofClientPatch.kt index 228703d337..0a7c3e752e 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/AbstractSpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/BaseSpoofClientPatch.kt @@ -1,14 +1,14 @@ package app.revanced.patches.reddit.customclients -import app.revanced.util.exception import app.revanced.patcher.PatchClass import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption +import app.revanced.util.exception -abstract class AbstractSpoofClientPatch( +abstract class BaseSpoofClientPatch( redirectUri: String, private val miscellaneousFingerprints: Set = emptySet(), private val clientIdFingerprints: Set = emptySet(), diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt index 0d7b8c918a..befc582bc7 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/baconreader/api/SpoofClientPatch.kt @@ -4,14 +4,14 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint.MethodFingerprintResult -import app.revanced.patches.reddit.customclients.AbstractSpoofClientPatch +import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.baconreader.api.fingerprints.GetAuthorizationUrlFingerprint import app.revanced.patches.reddit.customclients.baconreader.api.fingerprints.RequestTokenFingerprint import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Suppress("unused") -object SpoofClientPatch : AbstractSpoofClientPatch( +object SpoofClientPatch : BaseSpoofClientPatch( redirectUri = "http://baconreader.com/auth", clientIdFingerprints = setOf(GetAuthorizationUrlFingerprint, RequestTokenFingerprint), compatiblePackages = setOf( diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt index 8b48c0f437..e7a76441ff 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/boostforreddit/api/SpoofClientPatch.kt @@ -3,13 +3,13 @@ package app.revanced.patches.reddit.customclients.boostforreddit.api import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.fingerprint.MethodFingerprintResult -import app.revanced.patches.reddit.customclients.AbstractSpoofClientPatch +import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.GetClientIdFingerprint import app.revanced.patches.reddit.customclients.boostforreddit.api.fingerprints.LoginActivityOnCreateFingerprint @Suppress("unused") -object SpoofClientPatch : AbstractSpoofClientPatch( +object SpoofClientPatch : BaseSpoofClientPatch( redirectUri = "http://rubenmayayo.com", clientIdFingerprints = setOf(GetClientIdFingerprint), userAgentFingerprints = setOf(LoginActivityOnCreateFingerprint), diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch.kt index 59cc195a9d..0565bfefa7 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/infinityforreddit/api/SpoofClientPatch.kt @@ -5,14 +5,14 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.smali.toInstructions -import app.revanced.patches.reddit.customclients.AbstractSpoofClientPatch +import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.infinityforreddit.api.fingerprints.APIUtilsFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethodImplementation @Suppress("unused") -object SpoofClientPatch : AbstractSpoofClientPatch( +object SpoofClientPatch : BaseSpoofClientPatch( redirectUri = "infinity://localhost", clientIdFingerprints = setOf(APIUtilsFingerprint), compatiblePackages = setOf(CompatiblePackage("ml.docilealligator.infinityforreddit")) diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch.kt index 3dd1b7e9a3..7826956909 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/joeyforreddit/api/SpoofClientPatch.kt @@ -3,13 +3,13 @@ package app.revanced.patches.reddit.customclients.joeyforreddit.api import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.fingerprint.MethodFingerprintResult -import app.revanced.patches.reddit.customclients.AbstractSpoofClientPatch +import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.joeyforreddit.api.fingerprints.GetClientIdFingerprint import app.revanced.patches.reddit.customclients.joeyforreddit.detection.piracy.DisablePiracyDetectionPatch @Suppress("unused") -object SpoofClientPatch : AbstractSpoofClientPatch( +object SpoofClientPatch : BaseSpoofClientPatch( redirectUri = "https://127.0.0.1:65023/authorize_callback", clientIdFingerprints = setOf(GetClientIdFingerprint), compatiblePackages = setOf( diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt index 251efcf97c..ab110821ec 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/SpoofClientPatch.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.fingerprint.MethodFingerprintResult.MethodFingerprintScanResult.StringsScanResult.StringMatch -import app.revanced.patches.reddit.customclients.AbstractSpoofClientPatch +import app.revanced.patches.reddit.customclients.BaseSpoofClientPatch import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BasicAuthorizationFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.BuildAuthorizationStringFingerprint import app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints.GetUserAgentFingerprint @@ -14,7 +14,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Suppress("unused") -object SpoofClientPatch : AbstractSpoofClientPatch( +object SpoofClientPatch : BaseSpoofClientPatch( redirectUri = "redditisfun://auth", clientIdFingerprints = setOf(BuildAuthorizationStringFingerprint, BasicAuthorizationFingerprint), userAgentFingerprints = setOf(GetUserAgentFingerprint), diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/AbstractClientIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BaseClientIdFingerprint.kt similarity index 68% rename from src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/AbstractClientIdFingerprint.kt rename to src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BaseClientIdFingerprint.kt index 761987ba2d..108b4f97d0 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/AbstractClientIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BaseClientIdFingerprint.kt @@ -2,6 +2,6 @@ package app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint -internal abstract class AbstractClientIdFingerprint(string: String) : MethodFingerprint( +internal abstract class BaseClientIdFingerprint(string: String) : MethodFingerprint( strings = listOfNotNull("yyOCBp.RHJhDKd", string), ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BasicAuthorizationFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BasicAuthorizationFingerprint.kt index d524097fe2..30aacd6fd1 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BasicAuthorizationFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/customclients/redditisfun/api/fingerprints/BasicAuthorizationFingerprint.kt @@ -1,5 +1,5 @@ package app.revanced.patches.reddit.customclients.redditisfun.api.fingerprints -internal object BasicAuthorizationFingerprint : AbstractClientIdFingerprint( +internal object BasicAuthorizationFingerprint : BaseClientIdFingerprint( string = "fJOxVwBUyo*=f: - methodDef.name == "onCreate" && classDef.type.endsWith("Shell_HomeActivity;") - }, -) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportPatch.kt rename to src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt index dfb06c287a..5c118db6ac 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportPatch.kt @@ -2,14 +2,15 @@ package app.revanced.patches.shared.misc.gms import app.revanced.patcher.PatchClass import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportPatch.Constants.ACTIONS -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportPatch.Constants.AUTHORITIES -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportPatch.Constants.PERMISSIONS +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.ACTIONS +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.AUTHORITIES +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch.Constants.PERMISSIONS import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint import app.revanced.patches.shared.misc.gms.fingerprints.GmsCoreSupportFingerprint.GET_GMS_CORE_VENDOR_METHOD_NAME import app.revanced.util.exception @@ -24,39 +25,47 @@ import com.android.tools.smali.dexlib2.immutable.reference.ImmutableStringRefere import com.android.tools.smali.dexlib2.util.MethodUtil /** - * A patch that allows Google apps to run without root and under a different package name + * A patch that allows patched Google apps to run without root and under a different package name * by using GmsCore instead of Google Play Services. * * @param fromPackageName The package name of the original app. * @param toPackageName The package name to fall back to if no custom package name is specified in patch options. * @param primeMethodFingerprint The fingerprint of the "prime" method that needs to be patched. * @param earlyReturnFingerprints The fingerprints of methods that need to be returned early. - * @param abstractGmsCoreSupportResourcePatch The corresponding resource patch that is used to patch the resources. + * @param mainActivityOnCreateFingerprint The fingerprint of the main activity's onCreate method. + * @param integrationsPatchDependency The patch responsible for the integrations. + * @param gmsCoreSupportResourcePatch The corresponding resource patch that is used to patch the resources. * @param dependencies Additional dependencies of this patch. * @param compatiblePackages The compatible packages of this patch. * @param fingerprints The fingerprints of this patch. */ -abstract class AbstractGmsCoreSupportPatch( +abstract class BaseGmsCoreSupportPatch( private val fromPackageName: String, private val toPackageName: String, private val primeMethodFingerprint: MethodFingerprint, private val earlyReturnFingerprints: Set, - abstractGmsCoreSupportResourcePatch: AbstractGmsCoreSupportResourcePatch, + private val mainActivityOnCreateFingerprint: MethodFingerprint, + private val integrationsPatchDependency: PatchClass, + gmsCoreSupportResourcePatch: BaseGmsCoreSupportResourcePatch, dependencies: Set = setOf(), compatiblePackages: Set? = null, fingerprints: Set = emptySet(), ) : BytecodePatch( name = "GmsCore support", - description = "Allows Google apps to run without root and under a different package name " + + description = "Allows patched Google apps to run without root and under a different package name " + "by using GmsCore instead of Google Play Services.", - dependencies = setOf(ChangePackageNamePatch::class, abstractGmsCoreSupportResourcePatch::class) + dependencies, + dependencies = setOf( + ChangePackageNamePatch::class, + gmsCoreSupportResourcePatch::class, + integrationsPatchDependency + ) + dependencies, compatiblePackages = compatiblePackages, - fingerprints = setOf(GmsCoreSupportFingerprint) + fingerprints, + fingerprints = setOf(GmsCoreSupportFingerprint, mainActivityOnCreateFingerprint) + fingerprints, requiresIntegrations = true ) { init { // Manually register all options of the resource patch so that they are visible in the patch API. - abstractGmsCoreSupportResourcePatch.options.values.forEach(options::register) + gmsCoreSupportResourcePatch.options.values.forEach(options::register) } internal abstract val gmsCoreVendor: String? @@ -84,6 +93,12 @@ abstract class AbstractGmsCoreSupportPatch( // Return these methods early to prevent the app from crashing. earlyReturnFingerprints.toList().returnEarly() + // Check the availability of GmsCore. + mainActivityOnCreateFingerprint.result?.mutableMethod?.addInstruction( + 1, // Hack to not disturb other patches (such as the integrations patch). + "invoke-static {}, Lapp/revanced/integrations/youtube/patches/GmsCoreSupport;->checkAvailability()V" + ) ?: throw mainActivityOnCreateFingerprint.exception + // Change the vendor of GmsCore in ReVanced Integrations. GmsCoreSupportFingerprint.result?.mutableClass?.methods ?.single { it.name == GET_GMS_CORE_VENDOR_METHOD_NAME } diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt similarity index 94% rename from src/main/kotlin/app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch.kt rename to src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt index 72ced135ad..cfd80488bf 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/AbstractGmsCoreSupportResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/BaseGmsCoreSupportResourcePatch.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch -import app.revanced.util.mergeStrings +import app.revanced.patches.all.misc.resources.AddResourcesPatch import org.w3c.dom.Element import org.w3c.dom.Node @@ -18,12 +18,12 @@ import org.w3c.dom.Node * @param spoofedPackageSignature The signature of the package to spoof to. * @param dependencies Additional dependencies of this patch. */ -abstract class AbstractGmsCoreSupportResourcePatch( +abstract class BaseGmsCoreSupportResourcePatch( private val fromPackageName: String, private val toPackageName: String, private val spoofedPackageSignature: String, dependencies: Set = setOf() -) : ResourcePatch(dependencies = setOf(ChangePackageNamePatch::class) + dependencies) { +) : ResourcePatch(dependencies = setOf(ChangePackageNamePatch::class, AddResourcesPatch::class) + dependencies) { internal val gmsCoreVendorOption = stringPatchOption( key = "gmsCoreVendor", default = "com.mgoogle", @@ -39,7 +39,8 @@ abstract class AbstractGmsCoreSupportResourcePatch( protected val gmsCoreVendor by gmsCoreVendorOption override fun execute(context: ResourceContext) { - context.mergeStrings("gms/host/values/strings.xml") + AddResourcesPatch(BaseGmsCoreSupportResourcePatch::class) + context.patchManifest() context.addSpoofingMetadata() } diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/GmsCoreSupportFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/GmsCoreSupportFingerprint.kt index 5ecfa53c62..79be107f90 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/GmsCoreSupportFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/gms/fingerprints/GmsCoreSupportFingerprint.kt @@ -2,7 +2,7 @@ package app.revanced.patches.shared.misc.gms.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint -object GmsCoreSupportFingerprint : MethodFingerprint( +internal object GmsCoreSupportFingerprint : MethodFingerprint( customFingerprint = { _, classDef -> classDef.type.endsWith("GmsCoreSupport;") } diff --git a/src/main/kotlin/app/revanced/patches/shared/integrations/AbstractIntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt similarity index 65% rename from src/main/kotlin/app/revanced/patches/shared/integrations/AbstractIntegrationsPatch.kt rename to src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt index d9d051facc..9cf84495c9 100644 --- a/src/main/kotlin/app/revanced/patches/shared/integrations/AbstractIntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/integrations/BaseIntegrationsPatch.kt @@ -1,23 +1,43 @@ -package app.revanced.patches.shared.integrations +package app.revanced.patches.shared.misc.integrations import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint.RegisterResolver +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint.IRegisterResolver import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method -abstract class AbstractIntegrationsPatch( - private val integrationsDescriptor: String, +abstract class BaseIntegrationsPatch( private val hooks: Set ) : BytecodePatch(hooks) { + + @Deprecated( + "Use the constructor without the integrationsDescriptor parameter", + ReplaceWith("AbstractIntegrationsPatch(hooks)") + ) + @Suppress("UNUSED_PARAMETER") + constructor( + integrationsDescriptor: String, + 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." + ) + + hooks.forEach { hook -> + hook.invoke(INTEGRATIONS_CLASS_DESCRIPTOR) + } + } + /** * [MethodFingerprint] for integrations. * - * @param contextRegisterResolver A [RegisterResolver] to get the register. + * @param contextRegisterResolver A [IRegisterResolver] to get the register. * @see MethodFingerprint */ abstract class IntegrationsFingerprint( @@ -27,7 +47,7 @@ abstract class AbstractIntegrationsPatch( opcodes: Iterable? = null, strings: Iterable? = null, customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null, - private val contextRegisterResolver: (Method) -> Int = object : RegisterResolver {} + private val contextRegisterResolver: (Method) -> Int = object : IRegisterResolver {} ) : MethodFingerprint( returnType, accessFlags, @@ -48,16 +68,12 @@ abstract class AbstractIntegrationsPatch( } ?: throw PatchException("Could not find hook target fingerprint.") } - interface RegisterResolver : (Method) -> Int { + interface IRegisterResolver : (Method) -> Int { override operator fun invoke(method: Method) = method.implementation!!.registerCount - 1 } } - override fun execute(context: BytecodeContext) { - if (context.findClass(integrationsDescriptor) == null) throw PatchException( - "Integrations have not been merged yet. This patch can not succeed without merging the integrations." - ) - - for (hook in hooks) hook.invoke(integrationsDescriptor) + private companion object { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/shared/Utils;" } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/mapping/misc/ResourceMappingPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt similarity index 98% rename from src/main/kotlin/app/revanced/patches/shared/mapping/misc/ResourceMappingPatch.kt rename to src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt index c80a6b0c5b..c3b1ef20a7 100644 --- a/src/main/kotlin/app/revanced/patches/shared/mapping/misc/ResourceMappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/mapping/ResourceMappingPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.mapping.misc +package app.revanced.patches.shared.misc.mapping import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch 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 new file mode 100644 index 0000000000..d54601dae1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/BaseSettingsResourcePatch.kt @@ -0,0 +1,63 @@ +package app.revanced.patches.shared.misc.settings + +import app.revanced.patcher.PatchClass +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.BasePreference +import app.revanced.patches.shared.misc.settings.preference.IntentPreference +import app.revanced.util.ResourceGroup +import app.revanced.util.copyResources +import app.revanced.util.getNode +import org.w3c.dom.Node +import java.io.Closeable + +/** + * A resource patch that adds settings to a settings fragment. + * + * @param rootPreference A pair of an intent preference and the name of the fragment file to add it to. + * If null, no preference will be added. + * @param dependencies Additional dependencies of this patch. + */ +abstract class BaseSettingsResourcePatch( + private val rootPreference: Pair? = null, + dependencies: Set = emptySet() +) : ResourcePatch( + 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") + ) + + this.context = context + + AddResourcesPatch(BaseSettingsResourcePatch::class) + } + + override fun close() { + fun Node.addPreference(preference: BasePreference) { + 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) + } + + // Add the root preference to an existing fragment if needed. + rootPreference?.let { (intentPreference, fragment) -> + context.xmlEditor["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") + forEach { revancedPreferenceScreenNode.addPreference(it) } + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreference.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreference.kt new file mode 100644 index 0000000000..bad3d49be0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreference.kt @@ -0,0 +1,62 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document +import org.w3c.dom.Element + +/** + * Base preference class for all preferences. + * + * @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 tag The tag or full class name of the preference. + */ +@Suppress("MemberVisibilityCanBePrivate") +abstract class BasePreference( + val key: String? = null, + val titleKey: String = "${key}_title", + val summaryKey: String? = "${key}_summary", + val tag: String +) { + /** + * Serialize preference element to XML. + * Overriding methods should invoke super and operate on its return value. + * + * @param resourceCallback A callback for additional resources. + * @param ownerDocument Target document to create elements from. + * + * @return The serialized element. + */ + open fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element = + ownerDocument.createElement(tag).apply { + setAttribute("android:key", key) + setAttribute("android:title", "@string/${titleKey}") + summaryKey?.let { addSummary(it) } + } + + override fun hashCode(): Int { + var result = key?.hashCode() ?: 0 + result = 31 * result + titleKey.hashCode() + result = 31 * result + tag.hashCode() + return result + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as BasePreference + + if (key != other.key) return false + if (titleKey != other.titleKey) return false + if (tag != other.tag) return false + + return true + } + + companion object { + fun Element.addSummary(summaryKey: String, summaryType: SummaryType = SummaryType.DEFAULT) = + setAttribute("android:${summaryType.type}", "@string/$summaryKey") + } +} 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 new file mode 100644 index 0000000000..29bf976a8b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/BasePreferenceScreen.kt @@ -0,0 +1,93 @@ +package app.revanced.patches.shared.misc.settings.preference + +import java.io.Closeable + +abstract class BasePreferenceScreen( + private val root: MutableSet = mutableSetOf() +) : Closeable { + + override fun close() { + if (root.isEmpty()) return + + root.forEach { preference -> + commit(preference.transform()) + } + } + + /** + * Finalize and insert root preference into resource patch + */ + abstract fun commit(screen: PreferenceScreen) + + open inner class Screen( + key: String? = null, + titleKey: String = "${key}_title", + private val summaryKey: String? = "${key}_summary", + preferences: MutableSet = mutableSetOf(), + val categories: MutableSet = mutableSetOf() + ) : 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, + // 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() } + ) + } + + private fun ensureScreenInserted() { + // Add to screens if not yet done + if (!root.contains(this)) + root.add(this) + } + + fun addPreferences(vararg preferences: BasePreference) { + ensureScreenInserted() + this.preferences.addAll(preferences) + } + + open inner class Category( + key: String? = null, + titleKey: String = "${key}_title", + preferences: MutableSet = mutableSetOf() + ) : BasePreferenceCollection(key, titleKey, preferences) { + override fun transform(): PreferenceCategory { + return PreferenceCategory( + key, + titleKey, + preferences = preferences + ) + } + + fun addPreferences(vararg preferences: BasePreference) { + ensureScreenInserted() + + // Add to the categories if not done yet. + if (!categories.contains(this)) + categories.add(this) + + this.preferences.addAll(preferences) + } + } + } + + abstract class BasePreferenceCollection( + val key: String? = null, + val titleKey: String = "${key}_title", + val preferences: MutableSet = mutableSetOf() + ) { + abstract fun transform(): BasePreference + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt similarity index 73% rename from src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt rename to src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt index 7d3ec982da..e5142d92ee 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/InputType.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.settings.preference.impl +package app.revanced.patches.shared.misc.settings.preference enum class InputType(val type: String) { TEXT("text"), 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 new file mode 100644 index 0000000000..3c933a7299 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/IntentPreference.kt @@ -0,0 +1,56 @@ +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 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, + titleKey: String = "${key}_title", + summaryKey: String? = "${key}_summary", + tag: String = "Preference", + val intent: Intent, +) : BasePreference(null, titleKey, summaryKey, tag) { + + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + appendChild(ownerDocument.createElement("intent").also { intentNode -> + intentNode.setAttribute("android:data", intent.data) + intentNode.setAttribute("android:targetClass", intent.targetClass) + intentNode.setAttribute("android:targetPackage", intent.targetPackageSupplier()) + }) + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + if (!super.equals(other)) return false + + other as IntentPreference + + return intent == other.intent + } + + override fun hashCode(): Int { + var result = super.hashCode() + result = 31 * result + intent.hashCode() + return result + } + + data class Intent( + internal val data: String, + internal val targetClass: String, + internal val targetPackageSupplier: () -> String, + ) +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt new file mode 100644 index 0000000000..e0338d29c7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/ListPreference.kt @@ -0,0 +1,72 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.ArrayResource +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document + +/** + * List preference. + * + * @param key The preference key. If null, other parameters must be specified. + * @param titleKey The preference title key. + * @param summaryKey The preference summary key. + * @param tag The preference tag. + * @param entriesKey The entries array key. + * @param entryValuesKey The entry values array key. + */ +@Suppress("MemberVisibilityCanBePrivate") +class ListPreference( + key: String? = null, + titleKey: String = "${key}_title", + summaryKey: String? = "${key}_summary", + tag: String = "ListPreference", + val entriesKey: String? = "${key}_entries", + val entryValuesKey: String? = "${key}_entry_values" +) : BasePreference(key, titleKey, summaryKey, tag) { + var entries: ArrayResource? = null + private set + var entryValues: ArrayResource? = null + private set + + /** + * List preference. + * + * @param key The preference key. If null, other parameters must be specified. + * @param titleKey The preference title key. + * @param summaryKey The preference summary key. + * @param tag The preference tag. + * @param entries The entries array. + * @param entryValues The entry values array. + */ + constructor( + key: String? = null, + titleKey: String = "${key}_title", + summaryKey: String? = "${key}_summary", + tag: String = "ListPreference", + entries: ArrayResource, + entryValues: ArrayResource + ) : this(key, titleKey, summaryKey, tag, entries.name, entryValues.name) { + this.entries = entries + this.entryValues = entryValues + } + + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + val entriesArrayName = entries?.also { resourceCallback.invoke(it) }?.name ?: entriesKey + val entryValuesArrayName = entryValues?.also { resourceCallback.invoke(it) }?.name ?: entryValuesKey + + entriesArrayName?.let { + setAttribute( + "android:entries", + "@array/$it" + ) + } + + entryValuesArrayName?.let { + setAttribute( + "android:entryValues", + "@array/$it" + ) + } + } +} \ No newline at end of file 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 new file mode 100644 index 0000000000..b4b9155a65 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/NonInteractivePreference.kt @@ -0,0 +1,26 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document + +/** + * A non-interactive preference. + * + * @param key The preference key. + * @param summaryKey The preference summary key. + * @param tag The preference tag. + * @param selectable Whether the preference is selectable. + */ +@Suppress("MemberVisibilityCanBePrivate") +class NonInteractivePreference( + key: String, + summaryKey: String? = "${key}_summary", + tag: String = "Preference", + val selectable: Boolean = false +) : BasePreference(null, "${key}_title", summaryKey, tag) { + + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + setAttribute("android:selectable", selectable.toString()) + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceCategory.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceCategory.kt new file mode 100644 index 0000000000..67e82208f2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceCategory.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document + +/** + * A preference category. + * + * @param key The key of the preference. If null, other parameters must be specified. + * @param titleKey The key of the preference title. + * @param tag The tag or full class name of the preference. + * @param preferences The preferences in this category. + */ +@Suppress("MemberVisibilityCanBePrivate") +open class PreferenceCategory( + key: String? = null, + titleKey: String = "${key}_title", + tag: String = "PreferenceCategory", + val preferences: Set +) : BasePreference(key, titleKey, null, tag) { + + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + preferences.forEach { + appendChild(it.serialize(ownerDocument, resourceCallback)) + } + } +} 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 new file mode 100644 index 0000000000..f03dd23a94 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/PreferenceScreen.kt @@ -0,0 +1,30 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document + +/** + * A preference screen. + * + * @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 tag The tag or full class name of the preference. + * @param preferences The preferences in this screen. + */ +@Suppress("MemberVisibilityCanBePrivate") +open class PreferenceScreen( + key: String? = null, + titleKey: String = "${key}_title", + summaryKey: String? = "${key}_summary", + tag: String = "PreferenceScreen", + val preferences: Set +) : BasePreference(key, titleKey, summaryKey, tag) { + + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + preferences.forEach { + appendChild(it.serialize(ownerDocument, resourceCallback)) + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/SummaryType.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/SummaryType.kt similarity index 63% rename from src/main/kotlin/app/revanced/patches/shared/settings/preference/SummaryType.kt rename to src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/SummaryType.kt index 006f6986cf..ccf547b223 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/SummaryType.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/SummaryType.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.settings.preference +package app.revanced.patches.shared.misc.settings.preference enum class SummaryType(val type: String) { DEFAULT("summary"), ON("summaryOn"), OFF("summaryOff") diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/SwitchPreference.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/SwitchPreference.kt new file mode 100644 index 0000000000..e09d813a36 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/SwitchPreference.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document + +/** + * A switch preference. + * + * @param key The preference key. If null, other parameters must be specified. + * @param titleKey The preference title key. + * @param tag The preference tag. + * @param summaryOnKey The preference summary-on key. + * @param summaryOffKey The preference summary-off key. + */ +@Suppress("MemberVisibilityCanBePrivate") +class SwitchPreference( + key: String? = null, + titleKey: String = "${key}_title", + tag: String = "SwitchPreference", + val summaryOnKey: String = "${key}_summary_on", + val summaryOffKey: String = "${key}_summary_off" +) : BasePreference(key, titleKey, null, tag) { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + addSummary(summaryOnKey, SummaryType.ON) + addSummary(summaryOffKey, SummaryType.OFF) + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/TextPreference.kt b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/TextPreference.kt new file mode 100644 index 0000000000..d329a91778 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/misc/settings/preference/TextPreference.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.shared.misc.settings.preference + +import app.revanced.util.resource.BaseResource +import org.w3c.dom.Document + +/** + * A text preference. + * + * @param key The preference key. If null, other parameters must be specified. + * @param titleKey The preference title key. + * @param summaryKey The preference summary key. + * @param tag The preference tag. + * @param inputType The preference input type. + */ +@Suppress("MemberVisibilityCanBePrivate") +class TextPreference( + key: String? = null, + titleKey: String = "${key}_title", + summaryKey: String? = "${key}_summary", + tag: String = "app.revanced.integrations.shared.settings.preference.ResettableEditTextPreference", + val inputType: InputType = InputType.TEXT +) : BasePreference(key, titleKey, summaryKey, tag) { + + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + setAttribute("android:inputType", inputType.type) + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/AbstractSettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/settings/AbstractSettingsResourcePatch.kt deleted file mode 100644 index 4935370d8c..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/AbstractSettingsResourcePatch.kt +++ /dev/null @@ -1,121 +0,0 @@ -package app.revanced.patches.shared.settings - -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.util.DomFileEditor -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.addPreference -import app.revanced.patches.shared.settings.preference.addResource -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.util.ResourceGroup -import app.revanced.util.copyResources -import org.w3c.dom.Node -import java.io.Closeable - -/** - * Abstract settings resource patch - * - * @param preferenceFileName Name of the settings preference xml file - * @param sourceDirectory Source directory to copy the preference template from - */ -abstract class AbstractSettingsResourcePatch( - private val preferenceFileName: String, - private val sourceDirectory: String, -) : ResourcePatch(), Closeable { - override fun execute(context: ResourceContext) { - /* copy preference template from source dir */ - context.copyResources( - sourceDirectory, - ResourceGroup( - "xml", "$preferenceFileName.xml" - ) - ) - - /* prepare xml editors */ - stringsEditor = context.xmlEditor["res/values/strings.xml"] - arraysEditor = context.xmlEditor["res/values/arrays.xml"] - revancedPreferencesEditor = context.xmlEditor["res/xml/$preferenceFileName.xml"] - } - - internal companion object { - private var revancedPreferenceNode: Node? = null - private var stringsNode: Node? = null - private var arraysNode: Node? = null - - private var strings = mutableListOf() - - private var revancedPreferencesEditor: DomFileEditor? = null - set(value) { - field = value - revancedPreferenceNode = value.getNode("PreferenceScreen") - } - private var stringsEditor: DomFileEditor? = null - set(value) { - field = value - stringsNode = value.getNode("resources") - } - private var arraysEditor: DomFileEditor? = null - set(value) { - field = value - arraysNode = value.getNode("resources") - } - - /** - * Add a new string to the resources. - * - * @param identifier The key of the string. - * @param value The value of the string. - * @throws IllegalArgumentException if the string already exists. - */ - fun addString(identifier: String, value: String, formatted: Boolean) = - StringResource(identifier, value, formatted).include() - - /** - * Add an array to the resources. - * - * @param arrayResource The array resource to add. - */ - fun addArray(arrayResource: ArrayResource) = - arraysNode!!.addResource(arrayResource) { it.include() } - - /** - * Add a preference to the settings. - * - * @param preference The preference to add. - */ - fun addPreference(preference: BasePreference) = - revancedPreferenceNode!!.addPreference(preference) { it.include() } - - /** - * Add a new resource to the resources. - * - * @throws IllegalArgumentException if the resource already exists. - */ - internal fun BaseResource.include() { - when (this) { - is StringResource -> { - if (strings.any { it.name == name }) return - strings.add(this) - } - - is ArrayResource -> addArray(this) - else -> throw NotImplementedError("Unsupported resource type") - } - } - - internal fun DomFileEditor?.getNode(tagName: String) = this!!.file.getElementsByTagName(tagName).item(0) - } - - override fun close() { - // merge all strings, skip duplicates - strings.forEach { - stringsNode!!.addResource(it) - } - - revancedPreferencesEditor?.close() - stringsEditor?.close() - arraysEditor?.close() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt deleted file mode 100644 index a150aa6fe8..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt +++ /dev/null @@ -1,34 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * Base preference class for all preferences. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param tag The full class name for the preference. - * @param summary The summary of the preference. - */ -abstract class BasePreference( - val key: String?, - val title: StringResource, - val summary: StringResource? = null, - val tag: String -) { - /** - * Serialize preference element to XML. - * Overriding methods should invoke super and operate on its return value. - * @param ownerDocument Target document to create elements from. - * @param resourceCallback Called when a resource has been processed. - * @return The serialized element. - */ - open fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element = - ownerDocument.createElement(tag).apply { - if (key != null) setAttribute("android:key", key) - setAttribute("android:title", "@string/${title.also { resourceCallback.invoke(it) }.name}") - addSummary(summary?.also { resourceCallback.invoke(it) }) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt deleted file mode 100644 index 7e13127f0e..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt +++ /dev/null @@ -1,48 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource -import org.w3c.dom.Element -import org.w3c.dom.Node - -/** - * 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 = { }) { - appendChild(resource.serialize(ownerDocument, resourceCallback)) -} - -/** - * Add a preference node child to the settings. - * - * @param preference The preference to add. - * @param resourceCallback Called when a resource has been processed. - */ -internal fun Node.addPreference(preference: BasePreference, resourceCallback: ((BaseResource) -> Unit) = { }) { - appendChild(preference.serialize(ownerDocument, resourceCallback)) -} - -internal fun Element.addSummary(summaryResource: StringResource?, summaryType: SummaryType = SummaryType.DEFAULT) = - summaryResource?.let { summary -> - setAttribute("android:${summaryType.type}", "@string/${summary.name}") - } - -internal fun Element.addDefault(default: T) { - if (default is Boolean && !(default as Boolean)) return // No need to include the default, as no value already means 'false' - default?.let { - setAttribute( - "android:defaultValue", when (it) { - is Boolean -> it.toString() - is String -> it - else -> throw IllegalArgumentException("Unsupported default value type: ${it::class.java.name}") - } - ) - } -} - -internal fun CharSequence.removePunctuation(): String { - val punctuation = "\\p{P}+".toRegex() - return this.replace(punctuation, "") -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/DefaultBasePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/DefaultBasePreference.kt deleted file mode 100644 index 9371d48f8c..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/DefaultBasePreference.kt +++ /dev/null @@ -1,32 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource -import org.w3c.dom.Document - -/** - * Base preference class that also has a default value. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param tag The tag of the preference. - * @param summary The summary of the preference. - * @param default The default value of the preference. - */ -abstract class DefaultBasePreference( - key: String?, - title: StringResource, - summary: StringResource? = null, - tag: String, - val default: T? = null, -) : BasePreference(key, title, summary, tag) { - - /** - * Serialize preference element to XML. - * Overriding methods should invoke super and operate on its return value. - * @param ownerDocument Target document to create elements from. - * @param resourceCallback Called when a resource has been processed. - * @return The serialized element. - */ - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { addDefault(default) } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt deleted file mode 100644 index fa5e12f3ce..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt +++ /dev/null @@ -1,29 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import org.w3c.dom.Document - -// TODO: allow specifying an array resource file instead of using a list of StringResources -/** - * An array resource. - * - * @param name The name of the array resource. - * @param items The items of the array resource. - */ -class ArrayResource( - name: String, - val items: List -) : BaseResource(name, "string-array") { - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("name", name) - - items.forEach { item -> - resourceCallback.invoke(item) - - this.appendChild(ownerDocument.createElement("item").also { itemNode -> - itemNode.textContent = "@string/${item.name}" - }) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt deleted file mode 100644 index 37181267fa..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt +++ /dev/null @@ -1,32 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.DefaultBasePreference -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document - -/** - * List preference. - * - * @param key The key of the list preference. - * @param title The title of the list preference. - * @param entries The human-readable entries of the list preference. - * @param entryValues The entry values of the list preference. - * @param summary The summary of the list preference. - * @param default The default entry value of the list preference. - */ -class ListPreference( - key: String, - title: StringResource, - val entries: ArrayResource, - val entryValues: ArrayResource, - summary: StringResource? = null, - default: String? = null, -) : DefaultBasePreference(key, title, summary, "ListPreference", default) { - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("android:entries", "@array/${entries.also { resourceCallback.invoke(it) }.name}") - setAttribute("android:entryValues", "@array/${entryValues.also { resourceCallback.invoke(it) }.name}") - addSummary(summary) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt deleted file mode 100644 index ef08bc3e2f..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt +++ /dev/null @@ -1,35 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * A non interactive preference. - * - * Not backed by any preference key/value, - * and cannot be changed by or interacted with by the user. - * - * @param title The title of the preference. - * @param summary The summary of the text preference. - * @param selectable If this preference responds to tapping. - * Setting to 'true' restores the horizontal dividers on the top and bottom, - * but tapping will still do nothing since this Preference has no key. - */ -class NonInteractivePreference( - title: StringResource, - summary: StringResource?, - tag: String = "Preference", - // If androidx.preference is later used, this can be changed to the show top/bottom dividers feature. - val selectable: Boolean = false -) : BasePreference(null, title, summary, tag) { - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary?.also { resourceCallback.invoke(it) - setAttribute("android:selectable", selectable.toString()) - }) - } - } -} diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt deleted file mode 100644 index 463a1fce28..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt +++ /dev/null @@ -1,41 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.BaseResource -import org.w3c.dom.Document - -/** - * A preference object. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param summary The summary of the text preference. - * @param intent The intent of the preference. - */ -class Preference( - key: String, - title: StringResource, - summary: StringResource, - val intent: Intent -) : BasePreference(key, title, summary, "Preference") { - constructor( - title: StringResource, - summary: StringResource, - intent: Intent - ) : this("", title, summary, intent) - - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - this.appendChild(ownerDocument.createElement("intent").also { intentNode -> - intentNode.setAttribute("android:targetPackage", intent.targetPackage) - intentNode.setAttribute("android:data", intent.data) - intentNode.setAttribute("android:targetClass", intent.targetClass) - }) - } - - class Intent( - internal val targetPackage: String, - internal val data: String, - internal val targetClass: String - ) -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt deleted file mode 100644 index 633e8d7849..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt +++ /dev/null @@ -1,26 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.BaseResource -import org.w3c.dom.Document - -/** - * A preference category. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param preferences Child preferences of this category. - */ -open class PreferenceCategory( - key: String, - title: StringResource, - var preferences: List, - tag: String = "PreferenceCategory" -) : BasePreference(key, title, null, tag) { - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - for (childPreference in preferences) { - this.appendChild(childPreference.serialize(ownerDocument, resourceCallback)) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt deleted file mode 100644 index e0e435b23f..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt +++ /dev/null @@ -1,29 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document - -/** - * A preference screen. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param preferences Child preferences of this screen. - * @param summary The summary of the text preference. - */ -open class PreferenceScreen( - key: String, - title: StringResource, - var preferences: List, - summary: StringResource? = null -) : BasePreference(key, title, summary, "PreferenceScreen") { - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary?.also { resourceCallback.invoke(it) }) - - for (childPreference in preferences) - this.appendChild(childPreference.serialize(ownerDocument, resourceCallback)) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt deleted file mode 100644 index b3cd839723..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import org.w3c.dom.Document - -/** - * A string value. - * Represets a string in the strings.xml file. - * - * @param name The name of the string. - * @param value The value of the string. - * @param formatted If the string is formatted. If false, the attribute will be set. - */ -class StringResource( - name: String, - val value: String, - val formatted: Boolean = true -) : BaseResource(name, "string") { - - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - // if the string is un-formatted, explicitly add the formatted attribute - if (!formatted) setAttribute("formatted", "false") - - textContent = value - } -} diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt deleted file mode 100644 index 6623c3bf4f..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt +++ /dev/null @@ -1,36 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.DefaultBasePreference -import app.revanced.patches.shared.settings.preference.SummaryType -import app.revanced.patches.shared.settings.preference.addSummary -import app.revanced.patches.shared.settings.AbstractSettingsResourcePatch.Companion.include -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * A switch preference. - * - * @param key The key of the switch. - * @param title The title of the switch. - * @param summaryOn The summary to show when the preference is enabled. - * @param summaryOff The summary to show when the preference is disabled. - * @param userDialogMessage The message to show in a dialog when the user toggles the preference. - * @param default The default value of the switch. - */ -class SwitchPreference( - key: String, title: StringResource, - val summaryOn: StringResource, - val summaryOff: StringResource, - val userDialogMessage: StringResource? = null, - default: Boolean = false, -) : DefaultBasePreference( key, title, null, "SwitchPreference", default) { - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element { - userDialogMessage?.include() - - return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summaryOn.also { resourceCallback.invoke(it) }, SummaryType.ON) - addSummary(summaryOff.also { resourceCallback.invoke(it) }, SummaryType.OFF) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt deleted file mode 100644 index aaac8c5c01..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt +++ /dev/null @@ -1,29 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.DefaultBasePreference -import org.w3c.dom.Document - -/** - * A text preference. - * - * @param key The key of the text preference. - * @param title The title of the text preference. - * @param inputType The input type of the text preference. - * @param summary The summary of the text preference. - * @param default The default value of the text preference. - */ -class TextPreference( - key: String?, - title: StringResource, - summary: StringResource?, - val inputType: InputType = InputType.TEXT, - default: String? = null, - tag: String = "app.revanced.integrations.settingsmenu.ResettableEditTextPreference" -) : DefaultBasePreference(key, title, summary, tag, default) { - - override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = - super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("android:inputType", inputType.type) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt deleted file mode 100644 index c1148841c4..0000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt +++ /dev/null @@ -1,98 +0,0 @@ -package app.revanced.patches.shared.settings.util - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.impl.PreferenceCategory -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.removePunctuation -import java.io.Closeable - -abstract class AbstractPreferenceScreen( - private val root: MutableList = mutableListOf() -) : Closeable { - - override fun close() { - if (root.isEmpty()) - return - - for (preference in root.sortedBy { it.title }) { - commit(preference.transform()) - } - } - - /** - * Finalize and insert root preference into resource patch - */ - abstract fun commit(screen: PreferenceScreen) - - open inner class Screen( - key: String, - title: String, - val summary: String? = null, - preferences: MutableList = mutableListOf(), - val categories: MutableList = mutableListOf() - ) : BasePreferenceCollection(key, title, preferences) { - override fun transform() = PreferenceScreen( - key, - StringResource( - "${key}_title", title - ), - preferences.sortedWith( - compareBy( - { it is PreferenceScreen }, - { it.title.value.removePunctuation().lowercase() } - ) - ) + categories.sortedBy { - it.title.removePunctuation().lowercase() - }.map { - it.transform() - }, - summary?.let { summary -> - StringResource("${key}_summary", summary) - } - ) - - private fun ensureScreenInserted() { - // Add to screens if not yet done - if (!this@AbstractPreferenceScreen.root.contains(this)) - this@AbstractPreferenceScreen.root.add(this) - } - - fun addPreferences(vararg preferences: BasePreference) { - ensureScreenInserted() - this.preferences.addAll(preferences) - } - - open inner class Category( - key: String, - title: String, - preferences: MutableList = mutableListOf() - ) : BasePreferenceCollection(key, title, preferences) { - override fun transform(): PreferenceCategory { - return PreferenceCategory( - key, - StringResource("${key}_title", title), - preferences.sortedBy { it.title.value.removePunctuation().lowercase() } - ) - } - - fun addPreferences(vararg preferences: BasePreference) { - ensureScreenInserted() - - // Add to categories if not yet done - if (!this@Screen.categories.contains(this)) - this@Screen.categories.add(this) - - this.preferences.addAll(preferences) - } - } - } - - abstract class BasePreferenceCollection( - val key: String, - val title: String, - val preferences: MutableList = mutableListOf() - ) { - abstract fun transform(): BasePreference - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabResourcePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabResourcePatch.kt index d1093325d4..5f2ac4b22e 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/navbar/PremiumNavbarTabResourcePatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.spotify.navbar import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch @Patch(dependencies = [ResourceMappingPatch::class]) object PremiumNavbarTabResourcePatch : ResourcePatch() { diff --git a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt index 01f7c2f8ad..35a6f77fea 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt @@ -36,13 +36,13 @@ object FeedFilterPatch : BytecodePatch( addInstruction( returnFeedItemInstruction.location.index, "invoke-static { v$feedItemsRegister }, " + - "Lapp/revanced/tiktok/feedfilter/FeedItemsFilter;->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V" + "Lapp/revanced/integrations/tiktok/feedfilter/FeedItemsFilter;->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V" ) } ?: throw FeedApiServiceLIZFingerprint.exception SettingsStatusLoadFingerprint.result?.mutableMethod?.addInstruction( 0, - "invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsStatus;->enableFeedFilter()V" + "invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableFeedFilter()V" ) ?: throw SettingsStatusLoadFingerprint.exception } } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearModePatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearModePatch.kt index 7cf98bec27..7399e0b568 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearModePatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearModePatch.kt @@ -40,7 +40,7 @@ object RememberClearDisplayPatch : BytecodePatch( it.addInstructions( isEnabledIndex, "invoke-static { v$isEnabledRegister }, " + - "Lapp/revanced/tiktok/cleardisplay/RememberClearDisplayPatch;->rememberClearDisplayState(Z)V" + "Lapp/revanced/integrations/tiktok/cleardisplay/RememberClearDisplayPatch;->rememberClearDisplayState(Z)V" ) // endregion @@ -55,7 +55,7 @@ object RememberClearDisplayPatch : BytecodePatch( # Create a new clearDisplayEvent and post it to the EventBus (https://github.com/greenrobot/EventBus) # The state of clear display. - invoke-static { }, Lapp/revanced/tiktok/cleardisplay/RememberClearDisplayPatch;->getClearDisplayState()Z + invoke-static { }, Lapp/revanced/integrations/tiktok/cleardisplay/RememberClearDisplayPatch;->getClearDisplayState()Z move-result v3 if-eqz v3, :clear_display_disabled diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt index afb0889296..59b08b0ffd 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt @@ -69,7 +69,7 @@ object DownloadsPatch : BytecodePatch( addInstructionsWithLabels( 0, """ - invoke-static {}, Lapp/revanced/tiktok/download/DownloadsPatch;->shouldRemoveWatermark()Z + invoke-static {}, Lapp/revanced/integrations/tiktok/download/DownloadsPatch;->shouldRemoveWatermark()Z move-result v0 if-eqz v0, :noremovewatermark const/4 v0, 0x1 @@ -99,7 +99,7 @@ object DownloadsPatch : BytecodePatch( downloadUriMethod.addInstructions( secondIndex, """ - invoke-static {}, Lapp/revanced/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String; + invoke-static {}, Lapp/revanced/integrations/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String; move-result-object v0 """ ) @@ -107,7 +107,7 @@ object DownloadsPatch : BytecodePatch( downloadUriMethod.addInstructions( firstIndex, """ - invoke-static {}, Lapp/revanced/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String; + invoke-static {}, Lapp/revanced/integrations/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String; move-result-object v0 """ ) @@ -115,7 +115,7 @@ object DownloadsPatch : BytecodePatch( SettingsStatusLoadFingerprint to { addInstruction( 0, - "invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsStatus;->enableDownload()V" + "invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableDownload()V" ) } ).forEach { (fingerprint, patch) -> diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt index 3f7c17e7b4..35c477539b 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt @@ -1,49 +1,82 @@ package app.revanced.patches.tiktok.interaction.speed import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.tiktok.interaction.speed.fingerprints.SpeedControlParentFingerprint +import app.revanced.patches.tiktok.interaction.speed.fingerprints.GetSpeedFingerprint +import app.revanced.patches.tiktok.interaction.speed.fingerprints.OnRenderFirstFrameFingerprint +import app.revanced.patches.tiktok.interaction.speed.fingerprints.SetSpeedFingerprint import app.revanced.util.exception +import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction11x import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Playback speed", - description = "Enables the playback speed option for all videos.", + description = "Enables the playback speed option for all videos and " + + "retains the speed configurations in between videos.", compatiblePackages = [ CompatiblePackage("com.ss.android.ugc.trill", ["32.5.3"]), CompatiblePackage("com.zhiliaoapp.musically", ["32.5.3"]) ] ) @Suppress("unused") -object PlaybackSpeedPatch : BytecodePatch(setOf(SpeedControlParentFingerprint)) { +object PlaybackSpeedPatch : BytecodePatch( + setOf( + GetSpeedFingerprint, + OnRenderFirstFrameFingerprint, + SetSpeedFingerprint + ) +) { override fun execute(context: BytecodeContext) { - SpeedControlParentFingerprint.result?.mutableMethod?.apply { - val targetMethodCallIndex = indexOfFirstInstruction { - if (opcode == Opcode.INVOKE_STATIC) { - val paramsTypes = ((this as Instruction35c).reference as MethodReference).parameterTypes - paramsTypes.size == 1 && paramsTypes[0].contains("/Aweme;") - } else false - } + SetSpeedFingerprint.result?.let { onVideoSwiped -> + // Remember the playback speed of the current video. + GetSpeedFingerprint.result?.mutableMethod?.apply { + val injectIndex = indexOfFirstInstruction { getReference()?.returnType == "F" } + 2 + val register = getInstruction(injectIndex - 1).registerA - val isSpeedEnableMethod = context - .toMethodWalker(this) - .nextMethod(targetMethodCallIndex, true) - .getMethod() as MutableMethod + addInstruction( + injectIndex, + "invoke-static { v$register }," + + " Lapp/revanced/integrations/tiktok/speed/PlaybackSpeedPatch;->rememberPlaybackSpeed(F)V" + ) + } ?: throw GetSpeedFingerprint.exception - isSpeedEnableMethod.addInstructions( + // By default, the playback speed will reset to 1.0 at the start of each video. + // Instead, override it with the desired playback speed. + OnRenderFirstFrameFingerprint.result?.mutableMethod?.addInstructions( 0, """ - const/4 v0, 0x1 - return v0 + # Video playback location (e.g. home page, following page or search result page) retrieved using getEnterFrom method. + const/4 v0, 0x1 + invoke-virtual {p0, v0}, Lcom/ss/android/ugc/aweme/feed/panel/BaseListFragmentPanel;->getEnterFrom(Z)Ljava/lang/String; + move-result-object v0 + + # Model of current video retrieved using getCurrentAweme method. + invoke-virtual {p0}, Lcom/ss/android/ugc/aweme/feed/panel/BaseListFragmentPanel;->getCurrentAweme()Lcom/ss/android/ugc/aweme/feed/model/Aweme; + move-result-object v1 + + # Desired playback speed retrieved using getPlaybackSpeed method. + invoke-static {}, Lapp/revanced/integrations/tiktok/speed/PlaybackSpeedPatch;->getPlaybackSpeed()F + move-result-object v2 + invoke-static { v0, v1, v2 }, ${onVideoSwiped.method} + """ + ) ?: throw OnRenderFirstFrameFingerprint.exception + + // Force enable the playback speed option for all videos. + onVideoSwiped.mutableClass.methods.find { method -> method.returnType == "Z" }?.addInstructions( + 0, """ - ) - } ?: throw SpeedControlParentFingerprint.exception + const/4 v0, 0x1 + return v0 + """ + ) ?: throw PatchException("Failed to force enable the playback speed option.") + } ?: throw SetSpeedFingerprint.exception } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/GetSpeedFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/GetSpeedFingerprint.kt new file mode 100644 index 0000000000..f9845d4dc7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/GetSpeedFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.tiktok.interaction.speed.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object GetSpeedFingerprint : MethodFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("/BaseListFragmentPanel;") && methodDef.name == "onFeedSpeedSelectedEvent" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/OnRenderFirstFrameFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/OnRenderFirstFrameFingerprint.kt new file mode 100644 index 0000000000..59f930efea --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/OnRenderFirstFrameFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.tiktok.interaction.speed.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object OnRenderFirstFrameFingerprint : MethodFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("/BaseListFragmentPanel;") && methodDef.name == "onRenderFirstFrame" + } +) diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SetSpeedFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SetSpeedFingerprint.kt new file mode 100644 index 0000000000..97e566b97a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SetSpeedFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.tiktok.interaction.speed.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object SetSpeedFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf( + "Ljava/lang/String;", + "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", + "F" + ), + strings = listOf("enterFrom") +) diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt deleted file mode 100644 index 7edae32e14..0000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.tiktok.interaction.speed.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.AccessFlags - -internal object SpeedControlParentFingerprint : MethodFingerprint( - strings = listOf( - "onStopTrackingTouch, hasTouchMove=", - ", isCurVideoPaused: ", - "already_shown_edge_speed_guide" - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/IntegrationsPatch.kt index b13321c0c5..775a674773 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/IntegrationsPatch.kt @@ -1,11 +1,10 @@ package app.revanced.patches.tiktok.misc.integrations import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch import app.revanced.patches.tiktok.misc.integrations.fingerprints.InitFingerprint @Patch(requiresIntegrations = true) -object IntegrationsPatch : AbstractIntegrationsPatch( - "Lapp/revanced/tiktok/utils/ReVancedUtils;", +object IntegrationsPatch : BaseIntegrationsPatch( setOf(InitFingerprint) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt index 03b12c2149..f61e36bc12 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt @@ -1,6 +1,6 @@ package app.revanced.patches.tiktok.misc.integrations.fingerprints -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint internal object InitFingerprint : IntegrationsFingerprint( customFingerprint = { methodDef, _ -> diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt index d5980924d7..f3d5a2b0af 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/SettingsPatch.kt @@ -37,10 +37,10 @@ object SettingsPatch : BytecodePatch( ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/tiktok/settingsmenu/SettingsMenu;" + "Lapp/revanced/integrations/tiktok/settings/AdPersonalizationActivityHook;" private const val INITIALIZE_SETTINGS_METHOD_DESCRIPTOR = - "$INTEGRATIONS_CLASS_DESCRIPTOR->initializeSettings(" + + "$INTEGRATIONS_CLASS_DESCRIPTOR->initialize(" + "Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;" + ")Z" diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt index 2f390f238d..b689e785e8 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint internal object SettingsStatusLoadFingerprint : MethodFingerprint( customFingerprint = { methodDef, _ -> - methodDef.definingClass.endsWith("Lapp/revanced/tiktok/settingsmenu/SettingsStatus;") && + methodDef.definingClass.endsWith("Lapp/revanced/integrations/tiktok/settings/SettingsStatus;") && methodDef.name == "load" } ) \ No newline at end of file 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 137347aabb..39d412d264 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 @@ -85,7 +85,7 @@ object SpoofSimPatch : BytecodePatch() { with(SettingsStatusLoadFingerprint.result!!.mutableMethod) { addInstruction( 0, - "invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsStatus;->enableSimSpoof()V" + "invoke-static {}, Lapp/revanced/integrations/tiktok/settings/SettingsStatus;->enableSimSpoof()V" ) } } @@ -97,7 +97,7 @@ object SpoofSimPatch : BytecodePatch() { addInstructions( index + 2, """ - invoke-static {v$resultReg}, Lapp/revanced/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String; + invoke-static {v$resultReg}, Lapp/revanced/integrations/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String; move-result-object v$resultReg """ ) diff --git a/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/patch/ShowOnLockscreenPatch.kt b/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/patch/ShowOnLockscreenPatch.kt index 9e335aefa1..368879cfab 100644 --- a/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/patch/ShowOnLockscreenPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tudortmund/lockscreen/patch/ShowOnLockscreenPatch.kt @@ -25,7 +25,7 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference object ShowOnLockscreenPatch : BytecodePatch( setOf(BrightnessFingerprint) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/tudortmund/lockscreen/ShowOnLockscreenPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/tudortmund/lockscreen/ShowOnLockscreenPatch;" override fun execute(context: BytecodeContext) { BrightnessFingerprint.result?.mutableMethod?.apply { diff --git a/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/TimelineFilterPatch.kt b/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/TimelineFilterPatch.kt index 6b47bc1e55..4c41805026 100644 --- a/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/TimelineFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tumblr/timelinefilter/TimelineFilterPatch.kt @@ -60,7 +60,7 @@ object TimelineFilterPatch : BytecodePatch( fingerprint.result?.mutableMethod?.addInstructions( 0, "invoke-static {p$timelineObjectsRegister}, " + - "Lapp/revanced/tumblr/patches/TimelineFilterPatch;->" + + "Lapp/revanced/integrations/tumblr/patches/TimelineFilterPatch;->" + "filterTimeline(Ljava/util/List;)V" ) ?: throw fingerprint.exception } 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 bd25a2cb3a..75f9df43d3 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 @@ -7,8 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.twitch.ad.audio.fingerprints.AudioAdsPresenterPlayFingerprint import app.revanced.patches.twitch.misc.integrations.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.SettingsPatch @@ -16,7 +16,7 @@ import app.revanced.patches.twitch.misc.settings.SettingsPatch @Patch( name = "Block audio ads", description = "Blocks audio ads in streams and VODs.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "16.9.1"])], ) @Suppress("unused") @@ -24,12 +24,16 @@ object AudioAdsPatch : BytecodePatch( setOf(AudioAdsPresenterPlayFingerprint) ) { override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(SwitchPreference("revanced_block_audio_ads")) + // Block playAds call with(AudioAdsPresenterPlayFingerprint.result!!) { mutableMethod.addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/twitch/patches/AudioAdsPatch;->shouldBlockAudioAds()Z + invoke-static { }, Lapp/revanced/integrations/twitch/patches/AudioAdsPatch;->shouldBlockAudioAds()Z move-result v0 if-eqz v0, :show_audio_ads return-void @@ -37,24 +41,5 @@ object AudioAdsPatch : BytecodePatch( ExternalLabel("show_audio_ads", mutableMethod.getInstruction(0)) ) } - - SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( - SwitchPreference( - "revanced_block_audio_ads", - StringResource( - "revanced_block_audio_ads", - "Block audio ads" - ), - StringResource( - "revanced_block_audio_ads_on", - "Audio ads are blocked" - ), - StringResource( - "revanced_block_audio_ads_off", - "Audio ads are unblocked" - ), - default = true, - ) - ) } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt index 5b7f6d8d83..afc2e367d6 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/EmbeddedAdsPatch.kt @@ -1,23 +1,27 @@ package app.revanced.patches.twitch.ad.embedded -import app.revanced.util.exception 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.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.twitch.ad.embedded.fingerprints.CreateUsherClientFingerprint import app.revanced.patches.twitch.ad.video.VideoAdsPatch import app.revanced.patches.twitch.misc.integrations.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Block embedded ads", description = "Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.", - dependencies = [VideoAdsPatch::class, IntegrationsPatch::class, SettingsPatch::class], + dependencies = [ + VideoAdsPatch::class, + IntegrationsPatch::class, + SettingsPatch::class, + AddResourcesPatch::class + ], compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "16.9.1"])] ) @Suppress("unused") @@ -25,46 +29,22 @@ object EmbeddedAdsPatch : BytecodePatch( setOf(CreateUsherClientFingerprint) ) { override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.ADS.SURESTREAM.addPreferences( + ListPreference("revanced_block_embedded_ads") + ) + val result = CreateUsherClientFingerprint.result ?: throw CreateUsherClientFingerprint.exception // Inject OkHttp3 application interceptor result.mutableMethod.addInstructions( 3, """ - invoke-static {}, Lapp/revanced/twitch/patches/EmbeddedAdsPatch;->createRequestInterceptor()Lapp/revanced/twitch/api/RequestInterceptor; + invoke-static {}, Lapp/revanced/integrations/twitch/patches/EmbeddedAdsPatch;->createRequestInterceptor()Lapp/revanced/integrations/twitch/api/RequestInterceptor; move-result-object v2 invoke-virtual {v0, v2}, Lokhttp3/OkHttpClient${"$"}Builder;->addInterceptor(Lokhttp3/Interceptor;)Lokhttp3/OkHttpClient${"$"}Builder; """ ) - - SettingsPatch.PreferenceScreen.ADS.SURESTREAM.addPreferences( - ListPreference( - "revanced_block_embedded_ads", - StringResource( - "revanced_block_embedded_ads", - "Block embedded video ads" - ), - ArrayResource( - "revanced_hls_proxies", - listOf( - StringResource("revanced_proxy_disabled", "Disabled"), - StringResource("revanced_proxy_luminous", "Luminous proxy"), - StringResource("revanced_proxy_purpleadblock", "PurpleAdBlock proxy"), - ) - ), - ArrayResource( - "revanced_hls_proxies_values", - listOf( - StringResource("key_revanced_proxy_disabled", "disabled"), - StringResource("key_revanced_proxy_luminous", "luminous"), - StringResource("key_revanced_proxy_purpleadblock", "purpleadblock") - ) - ), - default = "luminous" - ) - ) - - SettingsPatch.addString("revanced_embedded_ads_service_unavailable", "%s is unavailable. Ads may show. Try switching to another ad block service in settings.") - SettingsPatch.addString("revanced_embedded_ads_service_failed", "%s server returned an error. Ads may show. Try switching to another ad block service in settings.") } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/BaseAdPatch.kt similarity index 98% rename from src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch.kt rename to src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/BaseAdPatch.kt index 7f92651bf6..776b338fbb 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/BaseAdPatch.kt @@ -7,7 +7,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.util.smali.ExternalLabel -abstract class AbstractAdPatch( +abstract class BaseAdPatch( val conditionCall: String, val skipLabelName: String, internal val fingerprints: Set = emptySet(), 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 00b134774b..ab00fe79af 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 @@ -1,6 +1,5 @@ package app.revanced.patches.twitch.ad.video -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels @@ -8,23 +7,24 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.twitch.ad.shared.util.AbstractAdPatch +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.twitch.ad.shared.util.BaseAdPatch import app.revanced.patches.twitch.ad.video.fingerprints.CheckAdEligibilityLambdaFingerprint import app.revanced.patches.twitch.ad.video.fingerprints.ContentConfigShowAdsFingerprint import app.revanced.patches.twitch.ad.video.fingerprints.GetReadyToShowAdFingerprint import app.revanced.patches.twitch.misc.integrations.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Block video ads", description = "Blocks video ads in streams and VODs.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "16.9.1"])] ) -object VideoAdsPatch : AbstractAdPatch( - "Lapp/revanced/twitch/patches/VideoAdsPatch;->shouldBlockVideoAds()Z", +object VideoAdsPatch : BaseAdPatch( + "Lapp/revanced/integrations/twitch/patches/VideoAdsPatch;->shouldBlockVideoAds()Z", "show_video_ads", setOf( ContentConfigShowAdsFingerprint, @@ -33,6 +33,10 @@ object VideoAdsPatch : AbstractAdPatch( ) ) { override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences(SwitchPreference("revanced_block_video_ads")) + /* Amazon ads SDK */ context.blockMethods( "Lcom/amazon/ads/video/player/AdsManagerImpl;", @@ -120,24 +124,5 @@ object VideoAdsPatch : AbstractAdPatch( """ ) } ?: throw ContentConfigShowAdsFingerprint.exception - - SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( - SwitchPreference( - "revanced_block_video_ads", - StringResource( - "revanced_block_video_ads", - "Block video ads" - ), - StringResource( - "revanced_block_video_ads_on", - "Video ads are blocked" - ), - StringResource( - "revanced_block_video_ads_off", - "Video ads are unblocked" - ), - default = true - ) - ) } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt index d5224f60d2..7cf83924be 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/ShowDeletedMessagesPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.twitch.chat.antidelete -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels @@ -9,19 +8,23 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.twitch.chat.antidelete.fingerprints.ChatUtilCreateDeletedSpanFingerprint import app.revanced.patches.twitch.chat.antidelete.fingerprints.DeletedMessageClickableSpanCtorFingerprint import app.revanced.patches.twitch.chat.antidelete.fingerprints.SetHasModAccessFingerprint import app.revanced.patches.twitch.misc.integrations.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Show deleted messages", description = "Shows deleted chat messages behind a clickable spoiler.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [ + IntegrationsPatch::class, + SettingsPatch::class, + AddResourcesPatch::class, + ], compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "16.9.1"])] ) @Suppress("unused") @@ -33,12 +36,21 @@ object ShowDeletedMessagesPatch : BytecodePatch( ) ) { private fun createSpoilerConditionInstructions(register: String = "v0") = """ - invoke-static {}, Lapp/revanced/twitch/patches/ShowDeletedMessagesPatch;->shouldUseSpoiler()Z + invoke-static {}, Lapp/revanced/integrations/twitch/patches/ShowDeletedMessagesPatch;->shouldUseSpoiler()Z move-result $register if-eqz $register, :no_spoiler """ override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences( + ListPreference( + key = "revanced_show_deleted_messages", + summaryKey = null, + ) + ) + // Spoiler mode: Force set hasModAccess member to true in constructor DeletedMessageClickableSpanCtorFingerprint.result?.mutableMethod?.apply { addInstructionsWithLabels( @@ -61,42 +73,13 @@ object ShowDeletedMessagesPatch : BytecodePatch( addInstructionsWithLabels( 0, """ - invoke-static {p2}, Lapp/revanced/twitch/patches/ShowDeletedMessagesPatch;->reformatDeletedMessage(Landroid/text/Spanned;)Landroid/text/Spanned; + invoke-static {p2}, Lapp/revanced/integrations/twitch/patches/ShowDeletedMessagesPatch;->reformatDeletedMessage(Landroid/text/Spanned;)Landroid/text/Spanned; move-result-object v0 if-eqz v0, :no_reformat return-object v0 """, ExternalLabel("no_reformat", getInstruction(0)) ) - } ?: throw ChatUtilCreateDeletedSpanFingerprint.exception - - SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences( - ListPreference( - "revanced_show_deleted_messages", - StringResource( - "revanced_show_deleted_messages_title", - "Show deleted messages" - ), - ArrayResource( - "revanced_deleted_messages", - listOf( - StringResource("revanced_deleted_messages_hide", "Do not show deleted messages"), - StringResource("revanced_deleted_messages_spoiler", "Hide deleted messages behind a spoiler"), - StringResource("revanced_deleted_messages_cross_out", "Show deleted messages as crossed-out text") - ) - ), - ArrayResource( - "revanced_deleted_messages_values", - listOf( - StringResource("key_revanced_deleted_messages_hide", "hide"), - StringResource("key_revanced_deleted_messages_spoiler", "spoiler"), - StringResource("key_revanced_deleted_messages_cross_out", "cross-out") - ) - ), - default = "cross-out" - ) - ) - - SettingsPatch.addString("revanced_deleted_msg", "message deleted") + } ?: throw ChatUtilCreateDeletedSpanFingerprint.exception } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt index a119669683..740f8cedf8 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/AutoClaimChannelPointsPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.twitch.chat.autoclaim -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -8,39 +7,27 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.twitch.chat.autoclaim.fingerprints.CommunityPointsButtonViewDelegateFingerprint import app.revanced.patches.twitch.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Auto claim channel points", description = "Automatically claim Channel Points.", - dependencies = [SettingsPatch::class], + dependencies = [SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "16.9.1"])] ) @Suppress("unused") -object AutoClaimChannelPointPatch : BytecodePatch( +object AutoClaimChannelPointsPatch : BytecodePatch( setOf(CommunityPointsButtonViewDelegateFingerprint) ) { override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences( - SwitchPreference( - "revanced_auto_claim_channel_points", - StringResource( - "revanced_auto_claim_channel_points", - "Automatically claim Channel Points" - ), - StringResource( - "revanced_auto_claim_channel_points_on", - "Channel Points are claimed automatically" - ), - StringResource( - "revanced_auto_claim_channel_points_off", - "Channel Points are not claimed automatically" - ), - default = true - ) + SwitchPreference("revanced_auto_claim_channel_points") ) CommunityPointsButtonViewDelegateFingerprint.result?.mutableMethod?.apply { @@ -48,7 +35,7 @@ object AutoClaimChannelPointPatch : BytecodePatch( addInstructionsWithLabels( lastIndex, // place in front of return-void """ - invoke-static {}, Lapp/revanced/twitch/patches/AutoClaimChannelPointsPatch;->shouldAutoClaim()Z + invoke-static {}, Lapp/revanced/integrations/twitch/patches/AutoClaimChannelPointsPatch;->shouldAutoClaim()Z move-result v0 if-eqz v0, :auto_claim 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 ac07bdc572..644b614c9b 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/debug/DebugModePatch.kt @@ -1,23 +1,23 @@ package app.revanced.patches.twitch.debug -import app.revanced.util.exception 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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.twitch.debug.fingerprints.IsDebugConfigEnabledFingerprint import app.revanced.patches.twitch.debug.fingerprints.IsOmVerificationEnabledFingerprint import app.revanced.patches.twitch.debug.fingerprints.ShouldShowDebugOptionsFingerprint import app.revanced.patches.twitch.misc.integrations.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Debug mode", description = "Enables Twitch's internal debugging mode.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("tv.twitch.android.app")], use = false ) @@ -30,6 +30,10 @@ object DebugModePatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences(SwitchPreference("revanced_twitch_debug_mode")) + listOf( IsDebugConfigEnabledFingerprint, IsOmVerificationEnabledFingerprint, @@ -39,31 +43,12 @@ object DebugModePatch : BytecodePatch( addInstructions( 0, """ - invoke-static {}, Lapp/revanced/twitch/patches/DebugModePatch;->isDebugModeEnabled()Z + invoke-static {}, Lapp/revanced/integrations/twitch/patches/DebugModePatch;->isDebugModeEnabled()Z move-result v0 return v0 """ ) } ?: throw it.exception } - - SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences( - SwitchPreference( - "revanced_debug_mode", - StringResource( - "revanced_debug_mode_enable", - "Enable debug mode" - ), - StringResource( - "revanced_debug_mode_on", - "Debug mode is enabled (not recommended)" - ), - StringResource( - "revanced_debug_mode_off", - "Debug mode is disabled" - ), - default = false, - ) - ) } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/IntegrationsPatch.kt index 66f6b035c1..0158adc64b 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/IntegrationsPatch.kt @@ -1,11 +1,10 @@ package app.revanced.patches.twitch.misc.integrations import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch import app.revanced.patches.twitch.misc.integrations.fingerprints.InitFingerprint @Patch(requiresIntegrations = true) -object IntegrationsPatch : AbstractIntegrationsPatch( - "Lapp/revanced/twitch/utils/ReVancedUtils;", +object IntegrationsPatch : BaseIntegrationsPatch( setOf(InitFingerprint) -) \ No newline at end of file +) diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt index 6ae7150d82..10ca2039be 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt @@ -1,6 +1,6 @@ package app.revanced.patches.twitch.misc.integrations.fingerprints -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint internal object InitFingerprint : IntegrationsFingerprint( customFingerprint = { methodDef, _ -> 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 36245a25d2..e8ec635c8c 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 @@ -1,6 +1,5 @@ package app.revanced.patches.twitch.misc.settings -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels @@ -12,14 +11,16 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.PreferenceCategory -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.PreferenceCategory +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.patches.shared.misc.settings.preference.BasePreferenceScreen import app.revanced.patches.twitch.misc.integrations.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.fingerprints.MenuGroupsOnClickFingerprint import app.revanced.patches.twitch.misc.settings.fingerprints.MenuGroupsUpdatedFingerprint import app.revanced.patches.twitch.misc.settings.fingerprints.SettingsActivityOnCreateFingerprint import app.revanced.patches.twitch.misc.settings.fingerprints.SettingsMenuItemEnumFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.immutable.ImmutableField import java.io.Closeable @@ -28,7 +29,11 @@ import java.io.Closeable @Patch( name = "Settings", description = "Adds settings menu to Twitch.", - dependencies = [IntegrationsPatch::class, SettingsResourcePatch::class], + dependencies = [ + IntegrationsPatch::class, + SettingsResourcePatch::class, + AddResourcesPatch::class + ], compatiblePackages = [ CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "16.9.1"]) ] @@ -46,21 +51,26 @@ object SettingsPatch : BytecodePatch( private const val REVANCED_SETTINGS_MENU_ITEM_TITLE_RES = "revanced_settings" private const val REVANCED_SETTINGS_MENU_ITEM_ICON_RES = "ic_settings" - private const val MENU_ITEM_ENUM_CLASS = "Ltv/twitch/android/feature/settings/menu/SettingsMenuItem;" - private const val MENU_DISMISS_EVENT_CLASS = "Ltv/twitch/android/feature/settings/menu/SettingsMenuViewDelegate\$Event\$OnDismissClicked;" + private const val MENU_ITEM_ENUM_CLASS_DESCRIPTOR = "Ltv/twitch/android/feature/settings/menu/SettingsMenuItem;" + private const val MENU_DISMISS_EVENT_CLASS_DESCRIPTOR = + "Ltv/twitch/android/feature/settings/menu/SettingsMenuViewDelegate\$Event\$OnDismissClicked;" - private const val INTEGRATIONS_PACKAGE = "app/revanced/twitch" - private const val SETTINGS_HOOKS_CLASS = "L$INTEGRATIONS_PACKAGE/settingsmenu/SettingsHooks;" - private const val REVANCED_UTILS_CLASS = "L$INTEGRATIONS_PACKAGE/utils/ReVancedUtils;" + private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations/twitch" + private const val ACTIVITY_HOOKS_CLASS_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settings/AppCompatActivityHook;" + private const val UTILS_CLASS_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/Utils;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + + PreferenceScreen.MISC.OTHER.addPreferences(SwitchPreference("revanced_debug")) + // Hook onCreate to handle fragment creation SettingsActivityOnCreateFingerprint.result?.apply { val insertIndex = mutableMethod.implementation!!.instructions.size - 2 mutableMethod.addInstructionsWithLabels( insertIndex, """ - invoke-static {p0}, $SETTINGS_HOOKS_CLASS->handleSettingsCreation(Landroidx/appcompat/app/AppCompatActivity;)Z + invoke-static {p0}, $ACTIVITY_HOOKS_CLASS_DESCRIPTOR->handleSettingsCreation(Landroidx/appcompat/app/AppCompatActivity;)Z move-result v0 if-eqz v0, :no_rv_settings_init return-void @@ -84,8 +94,8 @@ object SettingsPatch : BytecodePatch( mutableMethod.addInstructions( 0, """ - sget-object v0, $MENU_ITEM_ENUM_CLASS->$REVANCED_SETTINGS_MENU_ITEM_NAME:$MENU_ITEM_ENUM_CLASS - invoke-static {p1, v0}, $SETTINGS_HOOKS_CLASS->handleSettingMenuCreation(Ljava/util/List;Ljava/lang/Object;)Ljava/util/List; + sget-object v0, $MENU_ITEM_ENUM_CLASS_DESCRIPTOR->$REVANCED_SETTINGS_MENU_ITEM_NAME:$MENU_ITEM_ENUM_CLASS_DESCRIPTOR + invoke-static {p1, v0}, $ACTIVITY_HOOKS_CLASS_DESCRIPTOR->handleSettingMenuCreation(Ljava/util/List;Ljava/lang/Object;)Ljava/util/List; move-result-object p1 """ ) @@ -97,28 +107,18 @@ object SettingsPatch : BytecodePatch( mutableMethod.addInstructionsWithLabels( insertIndex, """ - invoke-static {p1}, $SETTINGS_HOOKS_CLASS->handleSettingMenuOnClick(Ljava/lang/Enum;)Z + invoke-static {p1}, $ACTIVITY_HOOKS_CLASS_DESCRIPTOR->handleSettingMenuOnClick(Ljava/lang/Enum;)Z move-result p2 if-eqz p2, :no_rv_settings_onclick - sget-object p1, $MENU_DISMISS_EVENT_CLASS->INSTANCE:$MENU_DISMISS_EVENT_CLASS + sget-object p1, $MENU_DISMISS_EVENT_CLASS_DESCRIPTOR->INSTANCE:$MENU_DISMISS_EVENT_CLASS_DESCRIPTOR invoke-virtual {p0, p1}, Ltv/twitch/android/core/mvp/viewdelegate/RxViewDelegate;->pushEvent(Ltv/twitch/android/core/mvp/viewdelegate/ViewDelegateEvent;)V return-void """, ExternalLabel("no_rv_settings_onclick", mutableMethod.getInstruction(insertIndex)) ) - } ?: throw MenuGroupsOnClickFingerprint.exception - - addString("revanced_settings", "ReVanced Settings", false) - addString("revanced_reboot_message", "Twitch needs to restart to apply your changes. Restart now?", false) - addString("revanced_reboot", "Restart", false) + } ?: throw MenuGroupsOnClickFingerprint.exception } - fun addString(identifier: String, value: String, formatted: Boolean = true) = - SettingsResourcePatch.addString(identifier, value, formatted) - - fun addPreferenceScreen(preferenceScreen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) = - SettingsResourcePatch.addPreferenceScreen(preferenceScreen) - private fun MethodFingerprintResult.injectMenuItem( name: String, value: Int, @@ -130,7 +130,7 @@ object SettingsPatch : BytecodePatch( ImmutableField( mutableMethod.definingClass, name, - MENU_ITEM_ENUM_CLASS, + MENU_ITEM_ENUM_CLASS_DESCRIPTOR, AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.ENUM or AccessFlags.STATIC, null, null, @@ -142,17 +142,17 @@ object SettingsPatch : BytecodePatch( mutableMethod.addInstructions( mutableMethod.implementation!!.instructions.size - 4, """ - new-instance v0, $MENU_ITEM_ENUM_CLASS + new-instance v0, $MENU_ITEM_ENUM_CLASS_DESCRIPTOR const-string v1, "$titleResourceName" - invoke-static {v1}, $REVANCED_UTILS_CLASS->getStringId(Ljava/lang/String;)I + invoke-static {v1}, $UTILS_CLASS_DESCRIPTOR->getStringId(Ljava/lang/String;)I move-result v1 const-string v3, "$iconResourceName" - invoke-static {v3}, $REVANCED_UTILS_CLASS->getDrawableId(Ljava/lang/String;)I + invoke-static {v3}, $UTILS_CLASS_DESCRIPTOR->getDrawableId(Ljava/lang/String;)I move-result v3 const-string v4, "$name" const/4 v5, $value - invoke-direct {v0, v4, v5, v1, v3}, $MENU_ITEM_ENUM_CLASS->(Ljava/lang/String;III)V - sput-object v0, $MENU_ITEM_ENUM_CLASS->$name:$MENU_ITEM_ENUM_CLASS + invoke-direct {v0, v4, v5, v1, v3}, $MENU_ITEM_ENUM_CLASS_DESCRIPTOR->(Ljava/lang/String;III)V + sput-object v0, $MENU_ITEM_ENUM_CLASS_DESCRIPTOR->$name:$MENU_ITEM_ENUM_CLASS_DESCRIPTOR """ ) } @@ -160,33 +160,32 @@ object SettingsPatch : BytecodePatch( /** * Preference screens patches should add their settings to. */ - internal object PreferenceScreen : AbstractPreferenceScreen() { - val ADS = CustomScreen("ads", "Ads", "Ad blocking settings") - val CHAT = CustomScreen("chat", "Chat", "Chat settings") - val MISC = CustomScreen("misc", "Misc", "Miscellaneous patches") + internal object PreferenceScreen : BasePreferenceScreen() { + val ADS = CustomScreen("revanced_ads_screen") + val CHAT = CustomScreen("revanced_chat_screen") + val MISC = CustomScreen("revanced_misc_screen") - internal class CustomScreen(key: String, title: String, summary: String) : Screen(key, title, summary) { + internal class CustomScreen(key: String) : Screen(key) { /* Categories */ - val GENERAL = CustomCategory("general", "General settings") - val OTHER = CustomCategory("other", "Other settings") - val CLIENT_SIDE = CustomCategory("client_ads", "Client-side ads") - val SURESTREAM = CustomCategory("surestream_ads", "Server-side surestream ads") + val GENERAL = CustomCategory("revanced_general_category") + val OTHER = CustomCategory("revanced_other_category") + val CLIENT_SIDE = CustomCategory("revanced_client_ads_category") + val SURESTREAM = CustomCategory("revanced_surestream_ads_category") - internal inner class CustomCategory(key: String, title: String) : Screen.Category(key, title) { + internal inner class CustomCategory(key: String) : Screen.Category(key) { /* For Twitch, we need to load our CustomPreferenceCategory class instead of the default one. */ override fun transform(): PreferenceCategory { return PreferenceCategory( key, - StringResource("${key}_title", title), - preferences.sortedBy { it.title.value }, - "app.revanced.twitch.settingsmenu.preference.CustomPreferenceCategory" + preferences = preferences, + tag = "app.revanced.integrations.twitch.settings.preference.CustomPreferenceCategory" ) } } } - override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) { - addPreferenceScreen(screen) + override fun commit(screen: app.revanced.patches.shared.misc.settings.preference.PreferenceScreen) { + SettingsResourcePatch += screen } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsResourcePatch.kt index f617846117..f547f4b77d 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/SettingsResourcePatch.kt @@ -1,36 +1,5 @@ package app.revanced.patches.twitch.misc.settings -import app.revanced.patches.shared.settings.AbstractSettingsResourcePatch -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen +import app.revanced.patches.shared.misc.settings.BaseSettingsResourcePatch -object SettingsResourcePatch : AbstractSettingsResourcePatch( -"revanced_prefs", -"twitch/settings" -) { - /* Companion delegates */ - - /** - * Add a new string to the resources. - * - * @param identifier The key of the string. - * @param value The value of the string. - * @throws IllegalArgumentException if the string already exists. - */ - fun addString(identifier: String, value: String, formatted: Boolean) = - AbstractSettingsResourcePatch.addString(identifier, value, formatted) - - /** - * Add an array to the resources. - * - * @param arrayResource The array resource to add. - */ - fun addArray(arrayResource: ArrayResource) = AbstractSettingsResourcePatch.addArray(arrayResource) - - /** - * Add a preference to the settings. - * - * @param preferenceScreen The name of the preference screen. - */ - fun addPreferenceScreen(preferenceScreen: PreferenceScreen) = AbstractSettingsResourcePatch.addPreference(preferenceScreen) -} \ No newline at end of file +object SettingsResourcePatch : BaseSettingsResourcePatch() \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt index 847a677020..d7e3687c85 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/JsonHookPatch.kt @@ -20,7 +20,7 @@ import java.io.InvalidClassException object JsonHookPatch : BytecodePatch( setOf(LoganSquareFingerprint) ), Closeable { - private const val JSON_HOOK_CLASS_NAMESPACE = "app/revanced/twitter/patches/hook/json" + private const val JSON_HOOK_CLASS_NAMESPACE = "app/revanced/integrations/twitter/patches/hook/json" private const val JSON_HOOK_PATCH_CLASS_DESCRIPTOR = "L$JSON_HOOK_CLASS_NAMESPACE/JsonHookPatch;" private const val BASE_PATCH_CLASS_NAME = "BaseJsonHook" private const val JSON_HOOK_CLASS_DESCRIPTOR = "L$JSON_HOOK_CLASS_NAMESPACE/$BASE_PATCH_CLASS_NAME;" diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch.kt similarity index 78% rename from src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.kt rename to src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatch.kt index 39d5c296ce..74c83fb185 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.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 BaseHookPatchPatch(private val hookClassDescriptor: String) : BytecodePatch() { +abstract class BaseHookPatch(private val hookClassDescriptor: String) : BytecodePatch() { 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/twitter/misc/hook/patch/ads/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/HideAdsHookPatch.kt similarity index 81% rename from src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/HideAdsPatch.kt rename to src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/HideAdsHookPatch.kt index 40ff710bca..8b12b64c0e 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/HideAdsHookPatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitter.misc.hook.patch.ads import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.twitter.misc.hook.json.JsonHookPatch -import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatchPatch +import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatch @Patch( name = "Hide ads", @@ -12,4 +12,4 @@ import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatchPatch compatiblePackages = [CompatiblePackage("com.twitter.android")] ) @Suppress("unused") -object HideAdsPatch : BaseHookPatchPatch("Lapp/revanced/twitter/patches/hook/patch/ads/AdsHook;") \ No newline at end of file +object HideAdsHookPatch : BaseHookPatch("Lapp/revanced/integrations/twitter/patches/hook/patch/ads/AdsHook;") \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch.kt index d510df7d5c..1897ce0f96 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/HideRecommendedUsersPatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitter.misc.hook.patch.recommendation import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.twitter.misc.hook.json.JsonHookPatch -import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatchPatch +import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatch @Patch( name = "Hide recommended users", @@ -11,6 +11,6 @@ import app.revanced.patches.twitter.misc.hook.patch.BaseHookPatchPatch compatiblePackages = [CompatiblePackage("com.twitter.android")] ) @Suppress("unused") -object HideRecommendedUsersPatch : BaseHookPatchPatch( - "Lapp/revanced/twitter/patches/hook/patch/recommendation/RecommendedUsersHook;" +object HideRecommendedUsersPatch : BaseHookPatch( + "Lapp/revanced/integrations/twitter/patches/hook/patch/recommendation/RecommendedUsersHook;" ) \ 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 521d3ac9e4..e53f018a30 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 @@ -15,7 +15,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c @Patch( name = "Hide ads", - description = "Removes general ads.", + description = "Adds options to remove general ads.", dependencies = [ HideGetPremiumPatch::class, HideAdsResourcePatch::class, @@ -24,15 +24,18 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", - [ + "com.google.android.youtube", [ "18.32.39", "18.37.36", "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -65,7 +68,7 @@ object HideAdsPatch : BytecodePatch() { .injectHideViewCall( insertIndex, viewRegister, - "Lapp/revanced/integrations/patches/components/AdsFilter;", + "Lapp/revanced/integrations/youtube/patches/components/AdsFilter;", "hideAdAttributionView" ) } 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 d7c0ac13ef..d7c3a359c1 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 @@ -3,9 +3,9 @@ package app.revanced.patches.youtube.ad.general import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +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 @@ -14,71 +14,29 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch.PreferenceScreen dependencies = [ LithoFilterPatch::class, SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ] ) object HideAdsResourcePatch : ResourcePatch() { private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/AdsFilter;" + "Lapp/revanced/integrations/youtube/patches/components/AdsFilter;" internal var adAttributionId: Long = -1 override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + PreferenceScreen.ADS.addPreferences( - SwitchPreference( - "revanced_hide_general_ads", - StringResource("revanced_hide_general_ads_title", "Hide general ads"), - StringResource("revanced_hide_general_ads_summary_on", "General ads are hidden"), - StringResource("revanced_hide_general_ads_summary_off", "General ads are shown") - ), - SwitchPreference( - "revanced_hide_fullscreen_ads", - StringResource("revanced_hide_fullscreen_ads_title", "Hide fullscreen ads"), - StringResource("revanced_hide_fullscreen_ads_summary_on", "Fullscreen ads are hidden"), - StringResource("revanced_hide_fullscreen_ads_summary_off", "Fullscreen ads are shown") - ), - SwitchPreference( - "revanced_hide_buttoned_ads", - StringResource("revanced_hide_buttoned_ads_title", "Hide buttoned ad"), - StringResource("revanced_hide_buttoned_ads_summary_on", "Buttoned ads are hidden"), - StringResource("revanced_hide_buttoned_ads_summary_off", "Buttoned ads are shown") - ), - SwitchPreference( - "revanced_hide_paid_content_ads", - StringResource("revanced_hide_paid_content_ads_title", "Hide paid content"), - StringResource("revanced_hide_paid_content_ads_summary_on", "Paid content is hidden"), - StringResource("revanced_hide_paid_content_ads_summary_off", "Paid content is shown") - ), - SwitchPreference( - "revanced_hide_self_sponsor_ads", - StringResource("revanced_hide_self_sponsor_ads_title", "Hide self sponsored cards"), - StringResource("revanced_hide_self_sponsor_ads_summary_on", "Self sponsored cards are hidden"), - StringResource("revanced_hide_self_sponsor_ads_summary_off", "Self sponsored cards are shown") - ), - SwitchPreference( - "revanced_hide_products_banner", - StringResource("revanced_hide_products_banner_title", "Hide banner to view products"), - StringResource("revanced_hide_products_banner_summary_on", "Banner is hidden"), - StringResource("revanced_hide_products_banner_summary_off", "Banner is shown") - ), - SwitchPreference( - "revanced_hide_shopping_links", - StringResource("revanced_hide_shopping_links_title", "Hide shopping links in video description"), - StringResource("revanced_hide_shopping_links_summary_on", "Shopping links are hidden"), - StringResource("revanced_hide_shopping_links_summary_off", "Shopping links are shown") - ), - SwitchPreference( - "revanced_hide_web_search_results", - StringResource("revanced_hide_web_search_results_title", "Hide web search results"), - StringResource("revanced_hide_web_search_results_summary_on", "Web search results are hidden"), - StringResource("revanced_hide_web_search_results_summary_off", "Web search results are shown") - ), - SwitchPreference( - "revanced_hide_merchandise_banners", - StringResource("revanced_hide_merchandise_banners_title", "Hide merchandise banners"), - StringResource("revanced_hide_merchandise_banners_summary_on", "Merchandise banners are hidden"), - StringResource("revanced_hide_merchandise_banners_summary_off", "Merchandise banners are shown") - ) + SwitchPreference("revanced_hide_general_ads"), + SwitchPreference("revanced_hide_fullscreen_ads"), + SwitchPreference("revanced_hide_buttoned_ads"), + SwitchPreference("revanced_hide_paid_content_ads"), + SwitchPreference("revanced_hide_self_sponsor_ads"), + SwitchPreference("revanced_hide_products_banner"), + SwitchPreference("revanced_hide_shopping_links"), + SwitchPreference("revanced_hide_web_search_results"), + SwitchPreference("revanced_hide_merchandise_banners") ) LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) 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 e337874a47..3f59ad17da 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 @@ -1,22 +1,22 @@ package app.revanced.patches.youtube.ad.getpremium -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.ad.getpremium.fingerprints.GetPremiumViewFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( description = "Hides YouTube Premium signup promotions under the video player.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -25,34 +25,24 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] ) object HideGetPremiumPatch : BytecodePatch(setOf(GetPremiumViewFingerprint)) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/HideGetPremiumPatch;" + "Lapp/revanced/integrations/youtube/patches/HideGetPremiumPatch;" override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.ADS.addPreferences( - SwitchPreference( - "revanced_hide_get_premium", - StringResource( - "revanced_hide_get_premium_title", - "Hide YouTube Premium promotions" - ), - StringResource( - "revanced_hide_get_premium_summary_on", - "YouTube Premium promotions under video player are hidden" - ), - StringResource( - "revanced_hide_get_premium_summary_off", - "YouTube Premium promotions under video player are shown" - ) - ) - ) + AddResourcesPatch(this::class) + + 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 3bf896f1d2..81215d6198 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 @@ -7,18 +7,19 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.ad.video.fingerprints.LoadVideoAdsFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( name = "Video ads", - description = "Removes ads in the video player.", + description = "Adds an option to remove ads in the video player.", dependencies = [ IntegrationsPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -29,8 +30,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -40,20 +45,15 @@ object VideoAdsPatch : BytecodePatch( setOf(LoadVideoAdsFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.ADS.addPreferences( - SwitchPreference( - "revanced_hide_video_ads", - StringResource("revanced_hide_video_ads_title", "Hide video ads"), - StringResource("revanced_hide_video_ads_summary_on", "Video ads are hidden"), - StringResource("revanced_hide_video_ads_summary_off", "Video ads are shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.ADS.addPreferences(SwitchPreference("revanced_hide_video_ads")) val loadVideoAdsFingerprintMethod = LoadVideoAdsFingerprint.result!!.mutableMethod loadVideoAdsFingerprintMethod.addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/VideoAdsPatch;->shouldShowAds()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/VideoAdsPatch;->shouldShowAds()Z move-result v0 if-nez v0, :show_video_ads return-void 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 556888f886..4d9795ce75 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 @@ -8,8 +8,8 @@ import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsBytecodePa import app.revanced.patches.youtube.video.information.VideoInformationPatch @Patch( - name = "Copy video url", - description = "Adds buttons in player to copy video links.", + name = "Copy video URL", + description = "Adds options to display buttons in the video player to copy video URLs.", dependencies = [ CopyVideoUrlResourcePatch::class, PlayerControlsBytecodePatch::class, @@ -17,22 +17,19 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", - [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "com.google.android.youtube", [ + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] ) @Suppress("unused") object CopyVideoUrlBytecodePatch : BytecodePatch() { - private const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/videoplayer" + private const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/youtube/videoplayer" private val BUTTONS_DESCRIPTORS = listOf( "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlButton;", "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;" 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 cb03d0f828..83a4456828 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 @@ -3,50 +3,31 @@ package app.revanced.patches.youtube.interaction.copyvideourl import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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 import app.revanced.util.ResourceGroup import app.revanced.util.copyResources -import app.revanced.util.mergeStrings @Patch( dependencies = [ SettingsPatch::class, - BottomControlsResourcePatch::class + BottomControlsResourcePatch::class, + AddResourcesPatch::class ] ) internal object CopyVideoUrlResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( PreferenceScreen( "revanced_copy_video_url_preference_screen", - StringResource("revanced_copy_video_url_preference_screen_title", "Copy video URL settings"), - listOf( - SwitchPreference( - "revanced_copy_video_url", - StringResource("revanced_copy_video_url_title", "Show copy video URL button"), - StringResource( - "revanced_copy_video_url_summary_on", - "Button is shown. Tap to copy video URL. Tap and hold to copy video URL with timestamp" - ), - StringResource("revanced_copy_video_url_summary_off", "Button is not shown") - ), - SwitchPreference( - "revanced_copy_video_url_timestamp", - StringResource("revanced_copy_video_url_timestamp_title", "Show copy timestamp URL button"), - StringResource( - "revanced_copy_video_url_timestamp_summary_on", - "Button is shown. Tap to copy video URL with timestamp. Tap and hold to copy video without timestamp" - ), - StringResource("revanced_copy_video_url_timestamp_summary_off", "Button is not shown") - ) - ), - StringResource( - "revanced_copy_video_url_preference_screen_summary", - "Settings related to copy URL buttons in video player" + preferences = setOf( + SwitchPreference("revanced_copy_video_url"), + SwitchPreference("revanced_copy_video_url_timestamp") ) ) ) @@ -59,7 +40,7 @@ internal object CopyVideoUrlResourcePatch : ResourcePatch() { ) ) - context.mergeStrings("copyvideourl/host/values/strings.xml") + AddResourcesPatch(this::class) BottomControlsResourcePatch.addControls("copyvideourl") } 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 1492ea970e..df6d45a48f 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 @@ -6,8 +6,8 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstructions import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.interaction.dialog.fingerprints.CreateDialogFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -16,12 +16,24 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @Patch( name = "Remove viewer discretion dialog", - description = "Removes the dialog that appears when you try to watch a video that has been age-restricted " + + 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.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube" + "com.google.android.youtube", [ + "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" + ] ) ] ) @@ -30,31 +42,13 @@ object RemoveViewerDiscretionDialogPatch : BytecodePatch( setOf(CreateDialogFingerprint) ) { private const val INTEGRATIONS_METHOD_DESCRIPTOR = - "Lapp/revanced/integrations/patches/RemoveViewerDiscretionDialogPatch;->" + + "Lapp/revanced/integrations/youtube/patches/RemoveViewerDiscretionDialogPatch;->" + "confirmDialog(Landroid/app/AlertDialog;)V" override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - SwitchPreference( - "revanced_remove_viewer_discretion_dialog", - StringResource( - "revanced_remove_viewer_discretion_dialog_title", - "Remove viewer discretion dialog" - ), - StringResource( - "revanced_remove_viewer_discretion_dialog_summary_on", - "Dialog will be removed" - ), - StringResource( - "revanced_remove_viewer_discretion_dialog_summary_off", - "Dialog will be shown" - ), - StringResource( - "revanced_remove_viewer_discretion_dialog_user_dialog_message", - "This does not bypass the age restriction, it just accepts it automatically." - ) - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.INTERACTIONS.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/ExternalDownloadsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt index be70a0d325..c65ad99f29 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 @@ -9,7 +9,7 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch @Patch( name = "External downloads", - description = "Adds support to download and save YouTube videos using an external app.", + description = "Adds support to download and save YouTube videos using an external downloader app.", dependencies = [ ExternalDownloadsResourcePatch::class, PlayerControlsBytecodePatch::class, @@ -17,22 +17,19 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch ], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", - [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "com.google.android.youtube", [ + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ), ] ) @Suppress("unused") object ExternalDownloadsBytecodePatch : BytecodePatch() { - private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/videoplayer/ExternalDownloadButton;" + private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;" override fun execute(context: BytecodeContext) { /* 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 3873a90972..656eb13de6 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 @@ -3,55 +3,37 @@ package app.revanced.patches.youtube.interaction.downloads import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.* +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.playercontrols.BottomControlsResourcePatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.util.ResourceGroup import app.revanced.util.copyResources -import app.revanced.util.mergeStrings @Patch( dependencies = [ BottomControlsResourcePatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class, ] ) internal object ExternalDownloadsResourcePatch : ResourcePatch() { - override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( PreferenceScreen( "revanced_external_downloader_preference_screen", - StringResource("revanced_external_downloader_preference_screen_title", "External download settings"), - listOf( - SwitchPreference( - "revanced_external_downloader", - StringResource("revanced_external_downloader_title", "Show external download button"), - StringResource("revanced_external_downloader_summary_on", "Download button shown in player"), - StringResource( - "revanced_external_downloader_summary_off", - "Download button not shown in player" - ) - ), - TextPreference( - "revanced_external_downloader_name", - StringResource("revanced_external_downloader_name_title", "Downloader package name"), - StringResource( - "revanced_external_downloader_name_summary", - "Package name of your installed external downloader app, such as NewPipe or Seal" - ), - InputType.TEXT - ) + preferences = setOf( + SwitchPreference("revanced_external_downloader"), + TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT) ), - StringResource( - "revanced_external_downloader_preference_screen_summary", - "Settings for using an external downloader" - ) ) ) - context.mergeStrings("downloads/host/values/strings.xml") - context.copyResources( "downloads", ResourceGroup("drawable", "revanced_yt_download_button.xml") 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 4578915f4b..b7b43d86ba 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 @@ -1,23 +1,23 @@ package app.revanced.patches.youtube.interaction.seekbar -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.interaction.seekbar.fingerprints.IsSwipingUpFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @Patch( name = "Disable precise seeking gesture", - description = "Disables the gesture that is used to seek precisely when swiping up on the seekbar.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to disable precise seeking when swiping up on the seekbar.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", @@ -27,8 +27,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -38,17 +42,14 @@ object DisablePreciseSeekingGesturePatch : BytecodePatch( setOf(IsSwipingUpFingerprint) ) { private const val INTEGRATIONS_METHOD_DESCRIPTOR = - "Lapp/revanced/integrations/patches/DisablePreciseSeekingGesturePatch;->" + + "Lapp/revanced/integrations/youtube/patches/DisablePreciseSeekingGesturePatch;->" + "disableGesture(Landroid/view/VelocityTracker;Landroid/view/MotionEvent;)V" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - SwitchPreference( - "revanced_disable_precise_seeking_gesture", - StringResource("revanced_disable_precise_seeking_gesture_title", "Disable precise seeking gesture"), - StringResource("revanced_disable_precise_seeking_gesture_summary_on", "Gesture is disabled"), - StringResource("revanced_disable_precise_seeking_gesture_summary_off", "Gesture is enabled"), - ) + SwitchPreference("revanced_disable_precise_seeking_gesture") ) IsSwipingUpFingerprint.result?.let { 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 de7bb5082f..86bc196732 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.interaction.seekbar -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -8,29 +7,34 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.interaction.seekbar.fingerprints.OnTouchEventHandlerFingerprint import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Seekbar tapping", - description = "Enables tap-to-seek on the seekbar of the video player.", + description = "Adds an option to enable tap-to-seek on the seekbar of the video player.", dependencies = [ - IntegrationsPatch::class, SettingsPatch::class], + IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -43,14 +47,9 @@ object EnableSeekbarTappingPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - SwitchPreference( - "revanced_seekbar_tapping", - StringResource("revanced_seekbar_tapping_title", "Enable seekbar tapping"), - StringResource("revanced_seekbar_tapping_summary_on", "Seekbar tapping is enabled"), - StringResource("revanced_seekbar_tapping_summary_off", "Seekbar tapping is disabled") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(SwitchPreference("revanced_seekbar_tapping")) // Find the required methods to tap the seekbar. val seekbarTappingMethods = OnTouchEventHandlerFingerprint.result?.let { @@ -85,7 +84,7 @@ object EnableSeekbarTappingPatch : BytecodePatch( addInstructionsWithLabels( insertIndex, """ - invoke-static { }, Lapp/revanced/integrations/patches/SeekbarTappingPatch;->seekbarTappingEnabled()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/SeekbarTappingPatch;->seekbarTappingEnabled()Z move-result v$freeRegister if-eqz v$freeRegister, :disabled ${oMethod.toInvokeInstructionString()} 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 b8e884a428..cc95388a00 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 @@ -1,35 +1,40 @@ package app.revanced.patches.youtube.interaction.seekbar -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 import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.interaction.seekbar.fingerprints.DoubleSpeedSeekNoticeFingerprint import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SlideToSeekFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Enable slide to seek", - description = "Enable slide to seek instead of playing at 2x speed when pressing and holding in the video player.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + 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.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) - ] + ], + use = false ) @Suppress("unused") object EnableSlideToSeekPatch : BytecodePatch( @@ -38,26 +43,12 @@ object EnableSlideToSeekPatch : BytecodePatch( DoubleSpeedSeekNoticeFingerprint ) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/SlideToSeekPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/SlideToSeekPatch;" override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - SwitchPreference( - "revanced_slide_to_seek", - StringResource( - "revanced_slide_to_seek_title", - "Enable slide to seek" - ), - StringResource( - "revanced_slide_to_seek_summary_on", - "Slide to seek is enabled" - ), - StringResource( - "revanced_slide_to_seek_summary_off", - "Slide to seek is not enabled" - ), - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.INTERACTIONS.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/SwipeControlsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt index 08f6dc5ced..a3d9640d99 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/SwipeControlsBytecodePatch.kt @@ -1,7 +1,5 @@ package app.revanced.patches.youtube.interaction.swipecontrols -import app.revanced.util.transformMethods -import app.revanced.util.traverseClassHierarchy import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage @@ -10,13 +8,15 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu import app.revanced.patches.youtube.interaction.swipecontrols.fingerprints.SwipeControlsHostActivityFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch -import app.revanced.patches.youtube.shared.fingerprints.WatchWhileActivityFingerprint +import app.revanced.patches.youtube.shared.fingerprints.MainActivityFingerprint +import app.revanced.util.transformMethods +import app.revanced.util.traverseClassHierarchy import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.immutable.ImmutableMethod @Patch( name = "Swipe controls", - description = "Adds volume and brightness swipe controls.", + description = "Adds options to enable and configure volume and brightness swipe controls.", dependencies = [ IntegrationsPatch::class, PlayerTypeHookPatch::class, @@ -31,8 +31,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -40,19 +44,19 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod @Suppress("unused") object SwipeControlsBytecodePatch : BytecodePatch( setOf( - WatchWhileActivityFingerprint, + MainActivityFingerprint, SwipeControlsHostActivityFingerprint ) ) { override fun execute(context: BytecodeContext) { val wrapperClass = SwipeControlsHostActivityFingerprint.result!!.mutableClass - val targetClass = WatchWhileActivityFingerprint.result!!.mutableClass + val targetClass = MainActivityFingerprint.result!!.mutableClass - // inject the wrapper class from integrations into the class hierarchy of WatchWhileActivity + // Inject the wrapper class from integrations into the class hierarchy of MainActivity. wrapperClass.setSuperClass(targetClass.superclass) targetClass.setSuperClass(wrapperClass.type) - // ensure all classes and methods in the hierarchy are non-final, so we can override them in integrations + // Ensure all classes and methods in the hierarchy are non-final, so we can override them in integrations. context.traverseClassHierarchy(targetClass) { accessFlags = accessFlags and AccessFlags.FINAL.value.inv() transformMethods { 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 58c6a2146a..de61545681 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 @@ -3,92 +3,36 @@ package app.revanced.patches.youtube.interaction.swipecontrols import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.* +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 import app.revanced.util.ResourceGroup import app.revanced.util.copyResources @Patch( - dependencies = [SettingsPatch::class] + dependencies = [SettingsPatch::class, AddResourcesPatch::class] ) internal object SwipeControlsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( PreferenceScreen( - "revanced_swipe_controls_preference_screen", - StringResource("revanced_swipe_controls_preference_screen_title", "Swipe controls"), - listOf( - SwitchPreference( - "revanced_swipe_brightness", - StringResource("revanced_swipe_brightness_title", "Enable brightness gesture"), - StringResource("revanced_swipe_brightness_summary_on", "Brightness swipe is enabled"), - StringResource("revanced_swipe_brightness_summary_off", "Brightness swipe is disabled") - ), - SwitchPreference( - "revanced_swipe_volume", - StringResource("revanced_swipe_volume_title", "Enable volume gesture"), - StringResource("revanced_swipe_volume_summary_on", "Volume swipe is enabled"), - StringResource("revanced_swipe_volume_summary_off", "Volume swipe is disabled") - ), - SwitchPreference( - "revanced_swipe_press_to_engage", - StringResource("revanced_swipe_press_to_engage_title", "Enable press-to-swipe gesture"), - StringResource("revanced_swipe_press_to_engage_summary_on", "Press-to-swipe is enabled"), - StringResource("revanced_swipe_press_to_engage_summary_off", "Press-to-swipe is disabled") - ), - SwitchPreference( - "revanced_swipe_haptic_feedback", - StringResource("revanced_swipe_haptic_feedback_title", "Enable haptic feedback"), - StringResource("revanced_swipe_haptic_feedback_summary_on", "Haptic feedback is enabled"), - StringResource("revanced_swipe_haptic_feedback_summary_off", "Haptic feedback is disabled") - ), - SwitchPreference( - "revanced_swipe_save_and_restore_brightness", - StringResource("revanced_swipe_save_and_restore_brightness_title", "Save and restore brightness"), - StringResource( - "revanced_swipe_save_and_restore_brightness_summary_on", - "Save and restore brightness when exiting or entering fullscreen" - ), - StringResource( - "revanced_swipe_save_and_restore_brightness_summary_off", - "Do not save and restore brightness when exiting or entering fullscreen" - ) - ), - TextPreference( - "revanced_swipe_overlay_timeout", - StringResource("revanced_swipe_overlay_timeout_title", "Swipe overlay timeout"), - StringResource( - "revanced_swipe_overlay_timeout_summary", - "The amount of milliseconds the overlay is visible" - ), - InputType.NUMBER - ), - TextPreference( - "revanced_swipe_text_overlay_size", - StringResource("revanced_swipe_text_overlay_size_title", "Swipe overlay text size"), - StringResource("revanced_swipe_text_overlay_size_summary", "The text size for swipe overlay"), - InputType.NUMBER - ), - TextPreference( - "revanced_swipe_overlay_background_alpha", - StringResource("revanced_swipe_overlay_background_alpha_title", "Swipe background visibility"), - StringResource( - "revanced_swipe_overlay_background_alpha_summary", - "The visibility of swipe overlay background" - ), - InputType.NUMBER - ), - TextPreference( - "revanced_swipe_threshold", - StringResource("revanced_swipe_threshold_title", "Swipe magnitude threshold"), - StringResource( - "revanced_swipe_threshold_summary", - "The amount of threshold for swipe to occur" - ), - InputType.NUMBER - ) + 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) ), - StringResource("revanced_swipe_controls_preference_screen_summary","Control volume and brightness") ) ) @@ -96,10 +40,10 @@ internal object SwipeControlsResourcePatch : ResourcePatch() { "swipecontrols", ResourceGroup( "drawable", - "ic_sc_brightness_auto.xml", - "ic_sc_brightness_manual.xml", - "ic_sc_volume_mute.xml", - "ic_sc_volume_normal.xml" + "revanced_ic_sc_brightness_auto.xml", + "revanced_ic_sc_brightness_manual.xml", + "revanced_ic_sc_volume_mute.xml", + "revanced_ic_sc_volume_normal.xml" ) ) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt index 14bdfb9ba4..a4b6100a69 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt @@ -8,6 +8,6 @@ internal object SwipeControlsHostActivityFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, parameters = listOf(), customFingerprint = { methodDef, _ -> - methodDef.definingClass == "Lapp/revanced/integrations/swipecontrols/SwipeControlsHostActivity;" + methodDef.definingClass == "Lapp/revanced/integrations/youtube/swipecontrols/SwipeControlsHostActivity;" } ) 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 c0f0f396c2..d5a77124a9 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 @@ -1,25 +1,25 @@ package app.revanced.patches.youtube.layout.autocaptions -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.autocaptions.fingerprints.StartVideoInformerFingerprint import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleButtonControllerFingerprint import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleTrackFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Disable auto captions", - description = "Disable forced captions from being automatically enabled.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to disable captions from being automatically enabled.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", @@ -29,8 +29,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ], @@ -40,14 +44,9 @@ object AutoCaptionsPatch : BytecodePatch( setOf(StartVideoInformerFingerprint, SubtitleButtonControllerFingerprint, SubtitleTrackFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_auto_captions", - StringResource("revanced_auto_captions_title", "Disable auto captions"), - StringResource("revanced_auto_captions_summary_on", "Auto captions are disabled"), - StringResource("revanced_auto_captions_summary_off", "Auto captions are enabled") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_auto_captions")) mapOf( StartVideoInformerFingerprint to 0, @@ -57,7 +56,7 @@ object AutoCaptionsPatch : BytecodePatch( 0, """ const/4 v0, 0x$enabled - sput-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z + sput-boolean v0, Lapp/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z """ ) ?: throw fingerprint.exception } @@ -65,10 +64,10 @@ object AutoCaptionsPatch : BytecodePatch( SubtitleTrackFingerprint.result?.mutableMethod?.addInstructionsWithLabels( 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->autoCaptionsEnabled()Z + invoke-static {}, Lapp/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch;->autoCaptionsEnabled()Z move-result v0 if-eqz v0, :auto_captions_enabled - sget-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z + sget-boolean v0, Lapp/revanced/integrations/youtube/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z if-nez v0, :auto_captions_enabled const/4 v0, 0x1 return v0 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 244eb7733d..b5a2143275 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 @@ -12,7 +12,7 @@ import java.nio.file.Files @Patch( name = "Custom branding", - description = "Changes the app name and icon to your choice (defaults to \"YouTube ReVanced\" and the ReVanced logo).", + description = "Applies a custom app name and icon. Defaults to \"YouTube ReVanced\" and the ReVanced logo.", compatiblePackages = [ CompatiblePackage("com.google.android.youtube") ], @@ -93,7 +93,7 @@ object CustomBrandingPatch : ResourcePatch() { ) } } - } else resourceGroups.forEach { context.copyResources("branding", it) } + } else resourceGroups.forEach { context.copyResources("custom-branding", it) } } } 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 new file mode 100644 index 0000000000..74ec3f7707 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/ChangeHeaderPatch.kt @@ -0,0 +1,137 @@ +package app.revanced.patches.youtube.layout.branding.header + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchException +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption +import app.revanced.util.ResourceGroup +import app.revanced.util.copyResources +import java.io.File + +@Patch( + 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") + ], + 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 val targetResourceDirectoryNames = arrayOf( + "xxxhdpi", + "xxhdpi", + "xhdpi", + "mdpi", + "hdpi", + ).map { dpi -> + "drawable-$dpi" + } + + private val variants = arrayOf("light", "dark") + + private val header by stringPatchOption( + key = "header", + default = REVANCED_BORDERLESS_HEADER_NAME, + 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, + ), + 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: + + ${targetResourceDirectoryNames.joinToString("\n") { "- $it" }} + + These folders must contain the following files: + + ${variants.joinToString("\n") { variant -> "- ${HEADER_NAME}_$variant.png" }} + """.trimIndent(), + required = true, + ) + + override fun execute(context: ResourceContext) { + // The directories to copy the header to. + val targetResourceDirectories = targetResourceDirectoryNames.mapNotNull { + context["res"].resolve(it).takeIf(File::exists) + } + // The files to replace in the target directories. + val targetResourceFiles = targetResourceDirectoryNames.map { directoryName -> + ResourceGroup( + directoryName, + *variants.map { variant -> "${HEADER_NAME}_$variant.png" }.toTypedArray() + ) + } + + /** + * A function that overwrites both header variants from [from] to [to] in the target resource directories. + */ + val overwriteFromTo: (String, String) -> Unit = { from: String, to: String -> + targetResourceDirectories.forEach { directory -> + variants.forEach { variant -> + val fromPath = directory.resolve("${from}_$variant.png") + val toPath = directory.resolve("${to}_$variant.png") + + fromPath.copyTo(toPath, true) + } + } + } + + // 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 toReVanced = { + // Copy the ReVanced header to the resource directories. + targetResourceFiles.forEach { context.copyResources("change-header/revanced", it) } + + // Overwrite the premium with the custom header as well. + toHeader() + } + val toReVancedBorderless = { + // Copy the ReVanced borderless header to the resource directories. + targetResourceFiles.forEach { context.copyResources("change-header/revanced-borderless", it) } + + // Overwrite the premium with the custom header as well. + 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 + + folder.listFiles { file -> file.isFile }?.forEach { + val targetResourceFile = targetDirectory.resolve(it.name) + + it.copyTo(targetResourceFile, true) + copiedReplacementImages = true + } + } + + if (!copiedReplacementImages) throw PatchException("Could not find any custom images resources in directory: $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 + else -> toCustom + }() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/PremiumHeadingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/PremiumHeadingPatch.kt index 167d18b758..5b88c8c286 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/PremiumHeadingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/PremiumHeadingPatch.kt @@ -1,62 +1,9 @@ package app.revanced.patches.youtube.layout.branding.header import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.booleanPatchOption -import kotlin.io.path.copyTo -@Patch( - name = "Premium heading", - description = "Show or hide the premium heading.", - compatiblePackages = [ - CompatiblePackage("com.google.android.youtube") - ] -) -@Suppress("unused") +@Deprecated("Use PremiumHeadingPatch instead.") object PremiumHeadingPatch : ResourcePatch() { - private const val DEFAULT_HEADING_RES = "yt_wordmark_header" - private const val PREMIUM_HEADING_RES = "yt_premium_wordmark_header" - - private val usePremiumHeading by booleanPatchOption( - key = "usePremiumHeading", - default = true, - title = "Use premium heading", - description = "Whether to use the premium heading.", - required = true, - ) - - override fun execute(context: ResourceContext) { - val resDirectory = context["res"] - - val (original, replacement) = if (usePremiumHeading!!) - PREMIUM_HEADING_RES to DEFAULT_HEADING_RES - else - DEFAULT_HEADING_RES to PREMIUM_HEADING_RES - - val variants = arrayOf("light", "dark") - - arrayOf( - "xxxhdpi", - "xxhdpi", - "xhdpi", - "hdpi", - "mdpi" - ).mapNotNull { dpi -> - resDirectory.resolve("drawable-$dpi").takeIf { it.exists() }?.toPath() - }.also { - if (it.isEmpty()) - throw PatchException("The drawable folder can not be found. Therefore, the patch can not be applied.") - }.forEach { path -> - - variants.forEach { mode -> - val fromPath = path.resolve("${original}_$mode.png") - val toPath = path.resolve("${replacement}_$mode.png") - - fromPath.copyTo(toPath, true) - } - } - } + override fun execute(context: ResourceContext) = ChangeHeaderPatch.execute(context) } 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 2ee75c96d7..928f3d7a1f 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 @@ -4,19 +4,20 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( name = "Hide video action buttons", - description = "Adds options to hide action buttons under a video.", + description = "Adds options to hide action buttons (such as the Download button) under videos.", dependencies = [ ResourceMappingPatch::class, - LithoFilterPatch::class + LithoFilterPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -27,8 +28,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -36,76 +41,26 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch @Suppress("unused") object HideButtonsPatch : ResourcePatch() { private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/ButtonsFilter;" + "Lapp/revanced/integrations/youtube/patches/components/ButtonsFilter;" override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( "revanced_hide_buttons_preference_screen", - StringResource("revanced_hide_buttons_preference_screen_title", "Hide action buttons"), - listOf( - SwitchPreference( - "revanced_hide_like_dislike_button", - StringResource("revanced_hide_like_dislike_button_title", "Hide like and dislike buttons"), - StringResource("revanced_hide_like_dislike_button_summary_on", "Like and dislike buttons are hidden"), - StringResource("revanced_hide_like_dislike_button_summary_off", "Like and dislike buttons are shown") - ), - SwitchPreference( - "revanced_hide_live_chat_button", - StringResource("revanced_hide_live_chat_button_title", "Hide live chat button"), - StringResource("revanced_hide_live_chat_button_summary_on", "Live chat button is hidden"), - StringResource("revanced_hide_live_chat_button_summary_off", "Live chat button is shown") - ), - SwitchPreference( - "revanced_hide_share_button", - StringResource("revanced_hide_share_button_title", "Hide share button"), - StringResource("revanced_hide_share_button_summary_on", "Share button is hidden"), - StringResource("revanced_hide_share_button_summary_off", "Share button is shown") - ), - SwitchPreference( - "revanced_hide_report_button", - StringResource("revanced_hide_report_button_title", "Hide report button"), - StringResource("revanced_hide_report_button_summary_on", "Report button is hidden"), - StringResource("revanced_hide_report_button_summary_off", "Report button is shown") - ), - SwitchPreference( - "revanced_hide_remix_button", - StringResource("revanced_hide_remix_button_title", "Hide remix button"), - StringResource("revanced_hide_remix_button_summary_on", "Remix button is hidden"), - StringResource("revanced_hide_remix_button_summary_off", "Remix button is shown") - ), - SwitchPreference( - "revanced_hide_download_button", - StringResource("revanced_hide_download_button_title", "Hide download button"), - StringResource("revanced_hide_download_button_summary_on", "Download button is hidden"), - StringResource("revanced_hide_download_button_summary_off", "Download button is shown") - ), - SwitchPreference( - "revanced_hide_thanks_button", - StringResource("revanced_hide_thanks_button_title", "Hide thanks button"), - StringResource("revanced_hide_thanks_button_summary_on", "Thanks button is hidden"), - StringResource("revanced_hide_thanks_button_summary_off", "Thanks button is shown") - ), - SwitchPreference( - "revanced_hide_clip_button", - StringResource("revanced_hide_clip_button_title", "Hide clip button"), - StringResource("revanced_hide_clip_button_summary_on", "Clip button is hidden"), - StringResource("revanced_hide_clip_button_summary_off", "Clip button is shown"), - ), - SwitchPreference( - "revanced_hide_playlist_button", - StringResource("revanced_hide_playlist_button_title", "Hide save to playlist button"), - StringResource("revanced_hide_playlist_button_summary_on", "Save button is hidden"), - StringResource("revanced_hide_playlist_button_summary_off", "Save button is shown") - ), - SwitchPreference( - "revanced_hide_shop_button", - StringResource("revanced_hide_shop_button_title", "Hide shop button"), - StringResource("revanced_hide_shop_button_summary_on", "Shop button is hidden"), - StringResource("revanced_hide_shop_button_summary_off", "Shop button is shown") - ) + 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"), + SwitchPreference("revanced_hide_download_button"), + SwitchPreference("revanced_hide_thanks_button"), + SwitchPreference("revanced_hide_clip_button"), + SwitchPreference("revanced_hide_playlist_button"), + SwitchPreference("revanced_hide_shop_button") ), - StringResource("revanced_hide_buttons_preference_screen_summary", "Hide or show buttons under videos") ) ) 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 0d2e40cf98..676eb5365a 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 @@ -1,7 +1,5 @@ package app.revanced.patches.youtube.layout.buttons.autoplay -import app.revanced.util.exception -import app.revanced.util.findIndexForIdResource import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -9,12 +7,14 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +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 import app.revanced.patches.youtube.shared.fingerprints.LayoutConstructorFingerprint +import app.revanced.util.exception +import app.revanced.util.findIndexForIdResource import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -22,11 +22,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Hide autoplay button", - description = "Hides the autoplay button in the video player.", + description = "Adds an option to hide the autoplay button in the video player.", dependencies = [ IntegrationsPatch::class, SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -37,8 +38,12 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -48,14 +53,9 @@ object HideAutoplayButtonPatch : BytecodePatch( setOf(LayoutConstructorFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_autoplay_button", - StringResource("revanced_hide_autoplay_button_title", "Hide autoplay button"), - StringResource("revanced_hide_autoplay_button_summary_on", "Autoplay button is hidden"), - StringResource("revanced_hide_autoplay_button_summary_off", "Autoplay button is shown") - ), - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_autoplay_button")) LayoutConstructorFingerprint.result?.mutableMethod?.apply { val layoutGenMethodInstructions = implementation!!.instructions @@ -78,7 +78,7 @@ object HideAutoplayButtonPatch : BytecodePatch( addInstructionsWithLabels( insertIndex, """ - invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z + invoke-static {}, Lapp/revanced/integrations/youtube/patches/HideAutoplayButtonPatch;->isButtonShown()Z move-result v$clobberRegister if-eqz v$clobberRegister, :hidden """, 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 55f09f2d84..60e4d51b75 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 @@ -5,8 +5,8 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleButtonControllerFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @@ -14,10 +14,11 @@ import com.android.tools.smali.dexlib2.Opcode @Patch( name = "Hide captions button", - description = "Hides the captions button in the video player.", + description = "Adds an option to hide the captions button in the video player.", dependencies = [ IntegrationsPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -28,8 +29,12 @@ import com.android.tools.smali.dexlib2.Opcode "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -39,14 +44,9 @@ object HideCaptionsButtonPatch : BytecodePatch( setOf(SubtitleButtonControllerFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_captions_button", - StringResource("revanced_hide_captions_button_title", "Hide captions button"), - StringResource("revanced_hide_captions_button_summary_on", "Captions button is hidden"), - StringResource("revanced_hide_captions_button_summary_off", "Captions button is shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_captions_button")) val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod @@ -58,7 +58,7 @@ object HideCaptionsButtonPatch : BytecodePatch( subtitleButtonControllerMethod.addInstruction( insertIndex, """ - invoke-static {v0}, Lapp/revanced/integrations/patches/HideCaptionsButtonPatch;->hideCaptionsButton(Landroid/widget/ImageView;)V + invoke-static {v0}, Lapp/revanced/integrations/youtube/patches/HideCaptionsButtonPatch;->hideCaptionsButton(Landroid/widget/ImageView;)V """ ) } 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 fe3f83329e..ee1f6943a6 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 @@ -6,17 +6,18 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +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 @Patch( name = "Hide cast button", - description = "Hides the cast button in the video player.", + description = "Adds an option to hide the cast button in the video player.", dependencies = [ IntegrationsPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage("com.google.android.youtube") @@ -24,14 +25,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch ) object HideCastButtonPatch : BytecodePatch() { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_cast_button", - StringResource("revanced_hide_cast_button_title", "Hide cast button"), - StringResource("revanced_hide_cast_button_summary_on", "Cast button is hidden"), - StringResource("revanced_hide_cast_button_summary_off", "Cast button is shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_cast_button")) val buttonClass = context.findClass("MediaRouteButton") ?: throw PatchException("MediaRouteButton class not found.") @@ -40,7 +36,7 @@ object HideCastButtonPatch : BytecodePatch() { addInstructions( 0, """ - invoke-static {p1}, Lapp/revanced/integrations/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I + invoke-static {p1}, Lapp/revanced/integrations/youtube/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I move-result p1 """ ) 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 5727bb93b9..de6304792a 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 @@ -1,29 +1,30 @@ package app.revanced.patches.youtube.layout.buttons.navigation -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 import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.layout.buttons.navigation.fingerprints.* import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUtils.injectHook import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Navigation buttons", - description = "Adds options to hide or change navigation buttons.", + description = "Adds options to hide and change navigation buttons (such as the Shorts button).", dependencies = [ IntegrationsPatch::class, SettingsPatch::class, - ResolvePivotBarFingerprintsPatch::class + ResolvePivotBarFingerprintsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -34,8 +35,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -45,61 +50,21 @@ object NavigationButtonsPatch : BytecodePatch( setOf(AddCreateButtonViewFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/NavigationButtonsPatch;" + "Lapp/revanced/integrations/youtube/patches/NavigationButtonsPatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( - "revanced_navigation_buttons_preference_screen", - StringResource("revanced_navigation_buttons_preference_screen_title", "Navigation buttons"), - listOf( - SwitchPreference( - "revanced_hide_home_button", - StringResource("revanced_hide_home_button_title", "Hide home button"), - StringResource("revanced_hide_home_button_summary_on", "Home button is hidden"), - StringResource("revanced_hide_home_button_summary_off", "Home button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_button", - StringResource("revanced_hide_shorts_button_title", "Hide Shorts button"), - StringResource("revanced_hide_shorts_button_summary_on", "Shorts button is hidden"), - StringResource("revanced_hide_shorts_button_summary_off", "Shorts button is shown") - ), - SwitchPreference( - "revanced_hide_subscriptions_button", - StringResource("revanced_hide_subscriptions_button_title", "Hide subscriptions button"), - StringResource( - "revanced_hide_subscriptions_button_summary_on", - "Home subscriptions is hidden" - ), - StringResource("revanced_hide_subscriptions_button_summary_off", "Home subscriptions is shown") - ), - SwitchPreference( - "revanced_hide_create_button", - StringResource("revanced_hide_create_button_title", "Hide create button"), - StringResource("revanced_hide_create_button_summary_on", "Create button is hidden"), - StringResource("revanced_hide_create_button_summary_off", "Create button is shown") - ), - SwitchPreference( - "revanced_switch_create_with_notifications_button", - StringResource( - "revanced_switch_create_with_notifications_button_title", - "Switch create with notifications button" - ), - StringResource( - "revanced_switch_create_with_notifications_button_summary_on", - "Create button is switched with notifications" - ), - StringResource( - "revanced_switch_create_with_notifications_button_summary_off", - "Create button is not switched with notifications" - ), - ), + key = "revanced_navigation_buttons_preference_screen", + preferences = setOf( + SwitchPreference("revanced_hide_home_button"), + SwitchPreference("revanced_hide_shorts_button"), + SwitchPreference("revanced_hide_subscriptions_button"), + SwitchPreference("revanced_hide_create_button"), + SwitchPreference("revanced_switch_create_with_notifications_button"), ), - StringResource( - "revanced_navigation_buttons_preference_screen_summary", - "Hide or change buttons in the navigation bar" - ) ) ) @@ -152,8 +117,8 @@ object NavigationButtonsPatch : BytecodePatch( AddCreateButtonViewFingerprint.result?.let { it.mutableMethod.apply { - val stringIndex = it.scanResult.stringsScanResult!!.matches.find { - match -> match.string == ANDROID_AUTOMOTIVE_STRING + val stringIndex = it.scanResult.stringsScanResult!!.matches.find { match -> + match.string == ANDROID_AUTOMOTIVE_STRING }!!.index val conditionalCheckIndex = stringIndex - 1 diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/ResolvePivotBarFingerprintsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/ResolvePivotBarFingerprintsPatch.kt index 393f65a8a0..eacab72b45 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/ResolvePivotBarFingerprintsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/ResolvePivotBarFingerprintsPatch.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.InitializeButtonsFingerprint import app.revanced.patches.youtube.layout.buttons.navigation.fingerprints.PivotBarConstructorFingerprint 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 22066eff13..70b040a47c 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 @@ -1,27 +1,28 @@ package app.revanced.patches.youtube.layout.buttons.player.hide -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 import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.buttons.player.hide.HidePlayerButtonsPatch.ParameterOffsets.HAS_NEXT import app.revanced.patches.youtube.layout.buttons.player.hide.HidePlayerButtonsPatch.ParameterOffsets.HAS_PREVIOUS import app.revanced.patches.youtube.layout.buttons.player.hide.fingerprints.PlayerControlsVisibilityModelFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc @Patch( name = "Hide player buttons", - description = "Hides previous and next buttons in the video player.", + description = "Adds an option to hide the previous and next buttons in the video player.", dependencies = [ IntegrationsPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -32,8 +33,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -43,23 +48,9 @@ object HidePlayerButtonsPatch : BytecodePatch( setOf(PlayerControlsVisibilityModelFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_player_buttons", - StringResource( - "revanced_hide_player_buttons_title", - "Hide previous & next video buttons" - ), - StringResource( - "revanced_hide_player_buttons_summary_on", - "Buttons are hidden" - ), - StringResource( - "revanced_hide_player_buttons_summary_off", - "Buttons are shown" - ) - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_player_buttons")) PlayerControlsVisibilityModelFingerprint.result?.apply { val callIndex = scanResult.patternScanResult!!.endIndex @@ -72,10 +63,10 @@ object HidePlayerButtonsPatch : BytecodePatch( mutableMethod.addInstructions( callIndex, """ - invoke-static { v$hasNextParameterRegister }, Lapp/revanced/integrations/patches/HidePlayerButtonsPatch;->previousOrNextButtonIsVisible(Z)Z + invoke-static { v$hasNextParameterRegister }, Lapp/revanced/integrations/youtube/patches/HidePlayerButtonsPatch;->previousOrNextButtonIsVisible(Z)Z move-result v$hasNextParameterRegister - invoke-static { v$hasPreviousParameterRegister }, Lapp/revanced/integrations/patches/HidePlayerButtonsPatch;->previousOrNextButtonIsVisible(Z)Z + invoke-static { v$hasPreviousParameterRegister }, Lapp/revanced/integrations/youtube/patches/HidePlayerButtonsPatch;->previousOrNextButtonIsVisible(Z)Z move-result v$hasPreviousParameterRegister """ ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt index 7286431a6b..4596995585 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/AlbumCardsPatch.kt @@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Hide album cards", - description = "Hides the album cards below the artist description.", + description = "Adds an option to hide album cards below artist descriptions.", dependencies = [ IntegrationsPatch::class, AlbumCardsResourcePatch::class @@ -27,8 +27,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -48,7 +52,7 @@ object AlbumCardsPatch : BytecodePatch( addInstruction( insertIndex, "invoke-static {v$albumCardViewRegister}, " + - "Lapp/revanced/integrations/patches/HideAlbumCardsPatch;" + + "Lapp/revanced/integrations/youtube/patches/HideAlbumCardsPatch;" + "->" + "hideAlbumCard(Landroid/view/View;)V" ) 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 2501d47923..e05b3e8b61 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 @@ -3,29 +3,25 @@ package app.revanced.patches.youtube.layout.hide.albumcards import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], ) internal object AlbumCardsResourcePatch : ResourcePatch() { internal var albumCardId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_album_cards", - StringResource("revanced_hide_album_cards_title", "Hide album cards"), - StringResource("revanced_hide_album_cards_summary_on", "Album cards are hidden"), - StringResource("revanced_hide_album_cards_summary_off", "Album cards are shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.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/BreakingNewsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsPatch.kt index 9ca0ae798a..d33428e05e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/BreakingNewsPatch.kt @@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Hide breaking news shelf", - description = "Hides the breaking news shelf on the homepage tab.", + description = "Adds an option to hide the breaking news shelf on the homepage tab.", dependencies = [ IntegrationsPatch::class, BreakingNewsResourcePatch::class @@ -27,8 +27,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -50,7 +54,7 @@ object BreakingNewsPatch : BytecodePatch( insertIndex, """ invoke-static {v$breakingNewsViewRegister}, - Lapp/revanced/integrations/patches/HideBreakingNewsPatch; + Lapp/revanced/integrations/youtube/patches/HideBreakingNewsPatch; -> hideBreakingNews(Landroid/view/View;)V """ 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 9de7b83dd4..31fb0b4a56 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 @@ -3,29 +3,25 @@ package app.revanced.patches.youtube.layout.hide.breakingnews import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], ) internal object BreakingNewsResourcePatch : ResourcePatch() { internal var horizontalCardListId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_breaking_news", - StringResource("revanced_hide_breaking_news_title", "Hide breaking news"), - StringResource("revanced_hide_breaking_news_summary_on", "Breaking news are hidden"), - StringResource("revanced_hide_breaking_news_summary_off", "Breaking news are shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.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 a2ef81a170..8e4c891c80 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 @@ -4,18 +4,19 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( name = "Comments", - description = "Hides components related to comments.", + description = "Adds options to hide components related to comments.", dependencies = [ SettingsPatch::class, - LithoFilterPatch::class + LithoFilterPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -26,8 +27,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -35,31 +40,21 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch @Suppress("unused") object CommentsPatch : ResourcePatch() { private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/CommentsFilter;" + "Lapp/revanced/integrations/youtube/patches/components/CommentsFilter;" override fun execute(context: ResourceContext) { - LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) - + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( "revanced_comments_preference_screen", - StringResource("revanced_comments_preference_screen_title", "Comments"), - listOf( - SwitchPreference( - "revanced_hide_comments_section", - StringResource("revanced_hide_comments_section_title", "Hide comments section"), - StringResource("revanced_hide_comments_section_summary_on", "Comment section is hidden"), - StringResource("revanced_hide_comments_section_summary_off", "Comment section is shown") - ), - SwitchPreference( - "revanced_hide_preview_comment", - StringResource("revanced_hide_preview_comment_title", "Hide preview comment"), - StringResource("revanced_hide_preview_comment_on", "Preview comment is hidden"), - StringResource("revanced_hide_preview_comment_off", "Preview comment is shown") - ) - ), - StringResource("revanced_comments_preference_screen_summary", "Manage the visibility of comments section components") + preferences = setOf( + SwitchPreference("revanced_hide_comments_section"), + SwitchPreference("revanced_hide_preview_comment") + ) ) ) + + LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt index 075a59e625..0065e13095 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/CrowdfundingBoxPatch.kt @@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Hide crowdfunding box", - description = "Hides the crowdfunding box between the player and video description.", + description = "Adds an option to hide the crowdfunding box between the player and video description.", dependencies = [ IntegrationsPatch::class, CrowdfundingBoxResourcePatch::class @@ -27,8 +27,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -38,7 +42,7 @@ object CrowdfundingBoxPatch : BytecodePatch( setOf(CrowdfundingBoxFingerprint) ) { private const val INTEGRATIONS_METHOD_DESCRIPTOR = - "Lapp/revanced/integrations/patches/HideCrowdfundingBoxPatch;->hideCrowdfundingBox(Landroid/view/View;)V" + "Lapp/revanced/integrations/youtube/patches/HideCrowdfundingBoxPatch;->hideCrowdfundingBox(Landroid/view/View;)V" override fun execute(context: BytecodeContext) { CrowdfundingBoxFingerprint.result?.let { 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 4df6484aa4..0ce74f7f02 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 @@ -3,29 +3,25 @@ package app.revanced.patches.youtube.layout.hide.crowdfundingbox import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], ) internal object CrowdfundingBoxResourcePatch : ResourcePatch() { internal var crowdfundingBoxId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_crowdfunding_box", - StringResource("revanced_hide_crowdfunding_box_title", "Hide crowdfunding box"), - StringResource("revanced_hide_crowdfunding_box_summary_on", "Crowdfunding box is hidden"), - StringResource("revanced_hide_crowdfunding_box_summary_off", "Crowdfunding box is shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.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/HideEndscreenCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt index 254a88d169..b7c76c7b7e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/HideEndscreenCardsPatch.kt @@ -16,7 +16,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c @Patch( name = "Hide endscreen cards", - description = "Hides the suggested video cards at the end of videos.", + description = "Adds an option to hide suggested video cards at the end of videos.", dependencies = [ IntegrationsPatch::class, HideEndscreenCardsResourcePatch::class @@ -30,8 +30,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -53,7 +57,7 @@ object HideEndscreenCardsPatch : BytecodePatch( addInstruction( insertIndex, - "invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V" + "invoke-static { v$viewRegister }, Lapp/revanced/integrations/youtube/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V" ) } } 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 87e65d6330..6f601391ef 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 @@ -3,15 +3,16 @@ package app.revanced.patches.youtube.layout.hide.endscreencards import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], ) internal object HideEndscreenCardsResourcePatch : ResourcePatch() { @@ -20,14 +21,9 @@ internal object HideEndscreenCardsResourcePatch : ResourcePatch() { internal var layoutVideo: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_endscreen_cards", - StringResource("revanced_hide_endscreen_cards_title", "Hide end screen cards"), - StringResource("revanced_hide_endscreen_cards_summary_on", "End screen cards are hidden"), - StringResource("revanced_hide_endscreen_cards_summary_off", "End screen cards are shown") - ), - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.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/HideFilterBarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt index 85a6495500..225b049bc5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/HideFilterBarPatch.kt @@ -16,7 +16,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Hide filter bar", - description = "Hides the filter bar in video feeds.", + description = "Adds options to hide the category bar at the top of video feeds.", dependencies = [HideFilterBarResourcePatch::class], compatiblePackages = [ CompatiblePackage( @@ -27,8 +27,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -42,7 +46,7 @@ object HideFilterBarPatch : BytecodePatch( ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/HideFilterBarPatch;" + "Lapp/revanced/integrations/youtube/patches/HideFilterBarPatch;" override fun execute(context: BytecodeContext) { FilterBarHeightFingerprint.patch { register -> 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 dedc114276..70ef188f5a 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 @@ -3,76 +3,28 @@ package app.revanced.patches.youtube.layout.hide.filterbar import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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 -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) +@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class]) internal object HideFilterBarResourcePatch : ResourcePatch() { internal var filterBarHeightId = -1L internal var relatedChipCloudMarginId = -1L internal var barContainerHeightId = -1L override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( - "revanced_hide_filter_bar_preference", - StringResource( - "revanced_hide_filter_bar_preference_title", - "Hide filter bar" - ), - listOf( - SwitchPreference( - "revanced_hide_filter_bar_feed_in_feed", - StringResource( - "revanced_hide_filter_bar_feed_in_feed_title", - "Hide in feed" - ), - StringResource( - "revanced_hide_filter_bar_feed_in_feed_summary_on", - "Hidden in feed" - ), - StringResource( - "revanced_hide_filter_bar_feed_in_feed_summary_off", - "Shown in feed" - ) - ), - SwitchPreference( - "revanced_hide_filter_bar_feed_in_search", - StringResource( - "revanced_hide_filter_bar_feed_in_search_title", - "Hide in search" - ), - StringResource( - "revanced_hide_filter_bar_feed_in_search_summary_on", - "Hidden in search" - ), - StringResource( - "revanced_hide_filter_bar_feed_in_search_summary_off", - "Shown in search" - ) - ), - SwitchPreference( - "revanced_hide_filter_bar_feed_in_related_videos", - StringResource( - "revanced_hide_filter_bar_feed_in_related_videos_title", - "Hide in related videos" - ), - StringResource( - "revanced_hide_filter_bar_feed_in_related_videos_summary_on", - "Hidden in related videos" - ), - StringResource( - "revanced_hide_filter_bar_feed_in_related_videos_summary_off", - "Shown in related videos" - ) - ), - ), - StringResource( - "revanced_hide_filter_bar_preference_summary", - "Manage the visibility of the filter bar in the feed, search and related videos" + key = "revanced_hide_filter_bar_preference", + preferences = setOf( + SwitchPreference("revanced_hide_filter_bar_feed_in_feed"), + SwitchPreference("revanced_hide_filter_bar_feed_in_search"), + SwitchPreference("revanced_hide_filter_bar_feed_in_related_videos"), ) ) ) @@ -82,6 +34,6 @@ internal object HideFilterBarResourcePatch : ResourcePatch() { barContainerHeightId = "bar_container_height".layoutResourceId() } - private fun String.layoutResourceId(type: String = "dimen") = - ResourceMappingPatch.resourceMappings.single { it.type == type && it.name == this }.id + private fun String.layoutResourceId(type: String = "dimen") = + ResourceMappingPatch.resourceMappings.single { it.type == type && it.name == this }.id } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt index 75fa8290ef..2689051dc5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/HideFloatingMicrophoneButtonPatch.kt @@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Hide floating microphone button", - description = "Hides the floating microphone button which appears in search.", + description = "Adds an option to hide the floating microphone button when searching.", dependencies = [HideFloatingMicrophoneButtonResourcePatch::class], compatiblePackages = [ CompatiblePackage( @@ -23,8 +23,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -34,7 +38,7 @@ object HideFloatingMicrophoneButtonPatch : BytecodePatch( setOf(ShowFloatingMicrophoneButtonFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/HideFloatingMicrophoneButtonPatch;" + "Lapp/revanced/integrations/youtube/patches/HideFloatingMicrophoneButtonPatch;" override fun execute(context: BytecodeContext) { ShowFloatingMicrophoneButtonFingerprint.result?.let { result -> 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 865462615a..92f8f42347 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 @@ -4,32 +4,25 @@ 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.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ] ) internal object HideFloatingMicrophoneButtonResourcePatch : ResourcePatch() { internal var fabButtonId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_floating_microphone_button", - StringResource( - "revanced_hide_floating_microphone_button_enabled_title", - "Hide floating microphone button" - ), - StringResource("revanced_hide_floating_microphone_button_summary_on", "Microphone button hidden"), - StringResource("revanced_hide_floating_microphone_button_summary_off", "Microphone button shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.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 6240eba9ad..421b123498 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 @@ -1,21 +1,21 @@ package app.revanced.patches.youtube.layout.hide.fullscreenambientmode -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.hide.fullscreenambientmode.fingerprints.InitializeAmbientModeFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Disable fullscreen ambient mode", - description = "Disables the ambient mode when in fullscreen.", - dependencies = [SettingsPatch::class, IntegrationsPatch::class], + description = "Adds an option to disable the ambient mode when in fullscreen.", + dependencies = [SettingsPatch::class, IntegrationsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -23,8 +23,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -34,25 +38,13 @@ object DisableFullscreenAmbientModePatch : BytecodePatch( setOf(InitializeAmbientModeFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/DisableFullscreenAmbientModePatch;" + "Lapp/revanced/integrations/youtube/patches/DisableFullscreenAmbientModePatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_disable_fullscreen_ambient_mode", - StringResource( - "revanced_disable_fullscreen_ambient_mode_title", - "Disable ambient mode in fullscreen" - ), - StringResource( - "revanced_disable_fullscreen_ambient_mode_summary_on", - "Ambient mode disabled" - ), - StringResource( - "revanced_disable_fullscreen_ambient_mode_summary_off", - "Ambient mode enabled" - ), - ) + SwitchPreference("revanced_disable_fullscreen_ambient_mode") ) InitializeAmbientModeFingerprint.result?.let { 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 78444f212f..5d8c261a50 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 @@ -10,7 +10,10 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.* +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.SwitchPreference +import app.revanced.patches.shared.misc.settings.preference.TextPreference import app.revanced.patches.youtube.layout.hide.general.fingerprints.ParseElementFromBufferFingerprint import app.revanced.patches.youtube.layout.hide.general.fingerprints.PlayerOverlayFingerprint import app.revanced.patches.youtube.layout.hide.general.fingerprints.ShowWatermarkFingerprint @@ -24,10 +27,11 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Hide layout components", - description = "Hides general layout components.", + description = "Adds options to hide general layout components.", dependencies = [ LithoFilterPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -37,8 +41,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -48,388 +56,60 @@ object HideLayoutComponentsPatch : BytecodePatch( setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint) ) { private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/LayoutComponentsFilter;" + "Lapp/revanced/integrations/youtube/patches/components/LayoutComponentsFilter;" private const val DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME = - "Lapp/revanced/integrations/patches/components/DescriptionComponentsFilter;" + "Lapp/revanced/integrations/youtube/patches/components/DescriptionComponentsFilter;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_gray_separator", - StringResource("revanced_hide_gray_separator_title", "Hide gray separator"), - StringResource("revanced_hide_gray_separator_summary_on", "Gray separators are hidden"), - StringResource("revanced_hide_gray_separator_summary_off", "Gray separators are shown") - ), - SwitchPreference( - "revanced_hide_join_membership_button", - StringResource("revanced_hide_join_membership_button_title", "Hide \\\'Join\\\' button"), - StringResource("revanced_hide_join_membership_button_summary_on", "Button is hidden"), - StringResource("revanced_hide_join_membership_button_summary_off", "Button is shown") - ), - SwitchPreference( - "revanced_hide_channel_watermark_title", - StringResource( - "revanced_hide_channel_watermark_title", - "Hide channel watermark in video player" - ), - StringResource("revanced_hide_channel_watermark_title_summary_on", "Watermark is hidden"), - StringResource("revanced_hide_channel_watermark_title_summary_off", "Watermark is shown") - ), - SwitchPreference( - "revanced_hide_for_you_shelf", - StringResource("revanced_hide_for_you_shelf_title", "Hide \\\'For you\\\' shelf in channel page"), - StringResource("revanced_hide_for_you_shelf_summary_on", "Shelf is hidden"), - StringResource("revanced_hide_for_you_shelf_summary_off", "Shelf is shown") - ), - SwitchPreference( - "revanced_hide_notify_me_button", - StringResource("revanced_hide_notify_me_button_title", "Hide \\\'Notify me\\\' button"), - StringResource("revanced_hide_notify_me_button_summary_on", "Button is hidden"), - StringResource("revanced_hide_notify_me_button_summary_off", "Button is shown") - ), - SwitchPreference( - "revanced_hide_timed_reactions", - StringResource("revanced_hide_timed_reactions_title", "Hide timed reactions"), - StringResource("revanced_hide_timed_reactions_summary_on", "Timed reactions are hidden"), - StringResource("revanced_hide_timed_reactions_summary_off", "Timed reactions are shown") - ), - SwitchPreference( - "revanced_hide_search_result_recommendations", - StringResource( - "revanced_hide_search_result_recommendations_title", - "Hide search result recommendations (e.g People also watched)" - ), - StringResource( - "revanced_hide_search_result_recommendations_summary_on", - "Recommendations are hidden" - ), - StringResource( - "revanced_hide_search_result_recommendations_summary_off", - "Recommendations are shown" - ) - ), - SwitchPreference( - "revanced_hide_search_result_shelf_header", - StringResource( - "revanced_hide_search_result_shelf_header_title", - "Hide search result shelf header" - ), - StringResource( - "revanced_hide_search_result_shelf_header_summary_on", - "Shelf header is hidden" - ), - StringResource( - "revanced_hide_search_result_shelf_header_summary_off", - "Shelf header is shown" - ) - ), - SwitchPreference( - "revanced_hide_channel_guidelines", - StringResource("revanced_hide_channel_guidelines_title", "Hide channel guidelines"), - StringResource( - "revanced_hide_channel_guidelines_summary_on", - "Channel guidelines are hidden" - ), - StringResource( - "revanced_hide_channel_guidelines_summary_off", - "Channel guidelines are shown" - ) - ), - SwitchPreference( - "revanced_hide_expandable_chip", - StringResource( - "revanced_hide_expandable_chip_title", - "Hide expandable chip under videos" - ), - StringResource( - "revanced_hide_expandable_chip_summary_on", - "Expandable chips are hidden" - ), - StringResource( - "revanced_hide_expandable_chip_summary_off", - "Expandable chips are shown" - ) - ), - SwitchPreference( - "revanced_hide_video_quality_menu_footer", - StringResource( - "revanced_hide_video_quality_menu_footer_title", - "Hide video quality menu footer" - ), - StringResource( - "revanced_hide_video_quality_menu_footer_summary_on", - "Video quality menu footer is hidden" - ), - StringResource( - "revanced_hide_video_quality_menu_footer_summary_off", - "Video quality menu footer is shown" - ) - ), - SwitchPreference( - "revanced_hide_chapters", - StringResource( - "revanced_hide_chapters_title", - "Hide chapters in the video description" - ), - StringResource( - "revanced_hide_chapters_summary_on", - "Chapters are hidden" - ), - StringResource( - "revanced_hide_chapters_summary_off", - "Chapters are shown" - ) - ), - SwitchPreference( - "revanced_hide_community_posts", - StringResource("revanced_hide_community_posts_title", "Hide community posts"), - StringResource("revanced_hide_community_posts_summary_on", "Community posts are hidden"), - StringResource("revanced_hide_community_posts_summary_off", "Community posts are shown") - ), - SwitchPreference( - "revanced_hide_compact_banner", - StringResource("revanced_hide_compact_banner_title", "Hide compact banners"), - StringResource("revanced_hide_compact_banner_summary_on", "Compact banners are hidden"), - StringResource("revanced_hide_compact_banner_summary_off", "Compact banners are shown") - ), - SwitchPreference( - "revanced_hide_movies_section", - StringResource("revanced_hide_movies_section_title", "Hide movies section"), - StringResource("revanced_hide_movies_section_summary_on", "Movies section is hidden"), - StringResource("revanced_hide_movies_section_summary_off", "Movies section is shown") - ), - SwitchPreference( - "revanced_hide_feed_survey", - StringResource("revanced_hide_feed_survey_title", "Hide feed surveys"), - StringResource("revanced_hide_feed_survey_summary_on", "Feed surveys are hidden"), - StringResource("revanced_hide_feed_survey_summary_off", "Feed surveys are shown") - ), - SwitchPreference( - "revanced_hide_community_guidelines", - StringResource("revanced_hide_community_guidelines_title", "Hide community guidelines"), - StringResource( - "revanced_hide_community_guidelines_summary_on", - "Community guidelines are hidden" - ), - StringResource( - "revanced_hide_community_guidelines_summary_off", - "Community guidelines are shown" - ) - ), - SwitchPreference( - "revanced_hide_subscribers_community_guidelines", - StringResource( - "revanced_hide_subscribers_community_guidelines_title", - "Hide subscribers community guidelines" - ), - StringResource( - "revanced_hide_subscribers_community_guidelines_summary_on", - "Subscribers community guidelines are hidden" - ), - StringResource( - "revanced_hide_subscribers_community_guidelines_summary_off", - "Subscribers community guidelines are shown" - ) - ), - SwitchPreference( - "revanced_hide_channel_member_shelf", - StringResource("revanced_hide_channel_member_shelf_title", "Hide channel member shelf"), - StringResource( - "revanced_hide_channel_member_shelf_summary_on", - "Channel member shelf is hidden" - ), - StringResource( - "revanced_hide_channel_member_shelf_summary_off", - "Channel member shelf is shown" - ) - ), - SwitchPreference( - "revanced_hide_emergency_box", - StringResource("revanced_hide_emergency_box_title", "Hide emergency boxes"), - StringResource("revanced_hide_emergency_box_summary_on", "Emergency boxes are hidden"), - StringResource("revanced_hide_emergency_box_summary_off", "Emergency boxes are shown") - ), - SwitchPreference( - "revanced_hide_info_panels", - StringResource("revanced_hide_info_panels_title", "Hide info panels"), - StringResource("revanced_hide_info_panels_summary_on", "Info panels are hidden"), - StringResource("revanced_hide_info_panels_summary_off", "Info panels are shown") - ), - SwitchPreference( - "revanced_hide_medical_panels", - StringResource("revanced_hide_medical_panels_title", "Hide medical panels"), - StringResource("revanced_hide_medical_panels_summary_on", "Medical panels are hidden"), - StringResource("revanced_hide_medical_panels_summary_off", "Medical panels are shown") - ), - SwitchPreference( - "revanced_hide_channel_bar", - StringResource("revanced_hide_channel_bar_title", "Hide channel bar"), - StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"), - StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown") - ), - SwitchPreference( - "revanced_hide_quick_actions", - StringResource("revanced_hide_quick_actions_title", "Hide quick actions in fullscreen"), - StringResource("revanced_hide_quick_actions_summary_on", "Quick actions are hidden"), - StringResource("revanced_hide_quick_actions_summary_off", "Quick actions are shown") - ), - SwitchPreference( - "revanced_hide_related_videos", - StringResource("revanced_hide_related_videos_title", "Hide related videos in quick actions"), - StringResource("revanced_hide_related_videos_summary_on", "Related videos are hidden"), - StringResource("revanced_hide_related_videos_summary_off", "Related videos are shown") - ), - SwitchPreference( - "revanced_hide_image_shelf", - StringResource("revanced_hide_image_shelf", "Hide image shelf in search results"), - StringResource("revanced_hide_image_shelf_summary_on", "Image shelf is hidden"), - StringResource("revanced_hide_image_shelf_summary_off", "Image shelf is shown") - ), - SwitchPreference( - "revanced_hide_latest_posts_ads", - StringResource("revanced_hide_latest_posts_ads_title", "Hide latest posts"), - StringResource("revanced_hide_latest_posts_ads_summary_on", "Latest posts are hidden"), - StringResource("revanced_hide_latest_posts_ads_summary_off", "Latest posts are shown") - ), - SwitchPreference( - "revanced_hide_mix_playlists", - StringResource("revanced_hide_mix_playlists_title", "Hide mix playlists"), - StringResource("revanced_hide_mix_playlists_summary_on", "Mix playlists are hidden"), - StringResource("revanced_hide_mix_playlists_summary_off", "Mix playlists are shown") - ), - SwitchPreference( - "revanced_hide_artist_cards", - StringResource("revanced_hide_artist_cards_title", "Hide artist cards"), - StringResource("revanced_hide_artist_cards_on", "Artist cards are hidden"), - StringResource("revanced_hide_artist_cards_off", "Artist cards are shown") - ), - SwitchPreference( - "revanced_hide_chips_shelf", - StringResource("revanced_hide_chips_shelf_title", "Hide chips shelf"), - StringResource("revanced_hide_chips_shelf_on", "Chips shelf is hidden"), - StringResource("revanced_hide_chips_shelf_off", "Chips shelf is shown") - ), - PreferenceScreen( + 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"), + 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_chips_shelf"), + app.revanced.patches.shared.misc.settings.preference.PreferenceScreen( "revanced_hide_description_components_preference_screen", - StringResource( - "revanced_hide_description_components_preference_screen_title", - "Hide components in the video description" - ), - listOf( - SwitchPreference( - "revanced_hide_info_cards_section", - StringResource( - "revanced_hide_info_cards_section_title", - "Hide info cards section" - ), - StringResource( - "revanced_hide_info_cards_section_summary_on", - "Info cards section is hidden" - ), - StringResource( - "revanced_hide_info_cards_section_summary_off", - "Info cards section is shown" - ) - ), - SwitchPreference( - "revanced_hide_game_section", - StringResource( - "revanced_hide_game_section_title", - "Hide game section" - ), - StringResource( - "revanced_hide_game_section_summary_on", - "Game section is hidden" - ), - StringResource( - "revanced_hide_game_section_summary_off", - "Game section is shown" - ) - ), - SwitchPreference( - "revanced_hide_music_section", - StringResource( - "revanced_hide_music_section_title", - "Hide music section" - ), - StringResource( - "revanced_hide_music_section_summary_on", - "Music section is hidden" - ), - StringResource( - "revanced_hide_music_section_summary_off", - "Music section is shown" - ) - ), - SwitchPreference( - "revanced_hide_podcast_section", - StringResource( - "revanced_hide_podcast_section_title", - "Hide podcast section" - ), - StringResource( - "revanced_hide_podcast_section_summary_on", - "Podcast section is hidden" - ), - StringResource( - "revanced_hide_podcast_section_summary_off", - "Podcast section is shown" - ) - ), - SwitchPreference( - "revanced_hide_transcript_section", - StringResource( - "revanced_hide_transcript_section_title", - "Hide transcript section" - ), - StringResource( - "revanced_hide_transcript_section_summary_on", - "Transcript section is hidden" - ), - StringResource( - "revanced_hide_transcript_section_summary_off", - "Transcript section is shown" - ) - ), - ), - StringResource( - "revanced_hide_description_components_preference_screen_summary", - "Hide components under the video description" + preferences = setOf( + 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"), ) ), - PreferenceScreen( + app.revanced.patches.shared.misc.settings.preference.PreferenceScreen( "revanced_custom_filter_preference_screen", - StringResource("revanced_custom_filter_preference_screen_title", "Custom filter"), - listOf( - SwitchPreference( - "revanced_custom_filter", - StringResource( - "revanced_custom_filter_title", - "Enable custom filter" - ), - StringResource( - "revanced_custom_filter_summary_on", - "Custom filter is enabled" - ), - StringResource( - "revanced_custom_filter_summary_off", - "Custom filter is disabled" - ) - ), + preferences = setOf( + SwitchPreference("revanced_custom_filter"), // TODO: This should be a dynamic ListPreference, which does not exist yet - TextPreference( - "revanced_custom_filter_strings", - StringResource("revanced_custom_filter_strings_title", "Custom filter"), - StringResource( - "revanced_custom_filter_strings_summary", - "List of component path builder strings to filter separated by new line" - ), - inputType = InputType.TEXT_MULTI_LINE - ) - ), - StringResource( - "revanced_custom_filter_preference_screen_summary", - "Hide components using custom filters" + TextPreference("revanced_custom_filter_strings", inputType = InputType.TEXT_MULTI_LINE) ) ) ) @@ -440,24 +120,21 @@ object HideLayoutComponentsPatch : BytecodePatch( // region Mix playlists ParseElementFromBufferFingerprint.result?.let { result -> - val returnEmptyComponentInstruction = result.mutableMethod.getInstructions() - .last { it.opcode == Opcode.INVOKE_STATIC } + val returnEmptyComponentInstruction = + result.mutableMethod.getInstructions().last { it.opcode == Opcode.INVOKE_STATIC } result.mutableMethod.apply { val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex val conversionContextRegister = getInstruction(consumeByteBufferIndex - 2).registerA - val byteBufferRegister = - getInstruction(consumeByteBufferIndex).registerD + 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) ) } @@ -474,8 +151,7 @@ object HideLayoutComponentsPatch : BytecodePatch( removeInstruction(index) addInstructions( - index, - """ + index, """ invoke-static {}, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->showWatermark()Z move-result p2 """ diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt index ffead3bc16..7426b1a9a6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/HideInfoCardsPatch.kt @@ -19,7 +19,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @Patch( name = "Hide info cards", - description = "Hides info cards in videos.", + description = "Adds an option to hide info cards that creators add in the video player.", dependencies = [ IntegrationsPatch::class, LithoFilterPatch::class, @@ -34,8 +34,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -48,7 +52,7 @@ object HideInfoCardsPatch : BytecodePatch( ) ) { private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/HideInfoCardsFilterPatch;" + "Lapp/revanced/integrations/youtube/patches/components/HideInfoCardsFilterPatch;" override fun execute(context: BytecodeContext) { InfocardsIncognitoFingerprint.also { @@ -62,7 +66,7 @@ object HideInfoCardsPatch : BytecodePatch( addInstruction( invokeInstructionIndex, "invoke-static {v${getInstruction(invokeInstructionIndex).registerC}}," + - " Lapp/revanced/integrations/patches/HideInfoCardsPatch;->hideInfoCardsIncognito(Landroid/view/View;)V" + " Lapp/revanced/integrations/youtube/patches/HideInfoCardsPatch;->hideInfoCardsIncognito(Landroid/view/View;)V" ) } @@ -75,7 +79,7 @@ object HideInfoCardsPatch : BytecodePatch( hideInfoCardsCallMethod.addInstructionsWithLabels( invokeInterfaceIndex, """ - invoke-static {}, Lapp/revanced/integrations/patches/HideInfoCardsPatch;->hideInfoCardsMethodCall()Z + invoke-static {}, Lapp/revanced/integrations/youtube/patches/HideInfoCardsPatch;->hideInfoCardsMethodCall()Z move-result v$toggleRegister if-nez v$toggleRegister, :hide_info_cards """, 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 fe3220fab8..cde96076d7 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 @@ -3,29 +3,25 @@ package app.revanced.patches.youtube.layout.hide.infocards import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], ) object HideInfocardsResourcePatch : ResourcePatch() { internal var drawerResourceId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_info_cards", - StringResource("revanced_hide_info_cards_title", "Hide info cards"), - StringResource("revanced_hide_info_cards_summary_on", "Info cards are hidden"), - StringResource("revanced_hide_info_cards_summary_off", "Info cards are shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.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/HideLoadMoreButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonPatch.kt index 47d4ff3fca..6609859109 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/HideLoadMoreButtonPatch.kt @@ -12,7 +12,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Hide \'Load more\' button", - description = "Hides the button under videos that loads similar videos.", + description = "Adds an option to hide the button under videos that loads similar videos.", dependencies = [HideLoadMoreButtonResourcePatch::class], compatiblePackages = [ CompatiblePackage( @@ -23,8 +23,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -34,7 +38,7 @@ object HideLoadMoreButtonPatch : BytecodePatch( setOf(HideLoadMoreButtonFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/HideLoadMoreButtonPatch;" + "Lapp/revanced/integrations/youtube/patches/HideLoadMoreButtonPatch;" override fun execute(context: BytecodeContext) { HideLoadMoreButtonFingerprint.result?.let { 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 1d07c57026..4ab73f3a3b 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 @@ -3,29 +3,25 @@ package app.revanced.patches.youtube.layout.hide.loadmorebutton import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ] ) internal object HideLoadMoreButtonResourcePatch : ResourcePatch() { internal var expandButtonDownId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_load_more_button", - StringResource("revanced_hide_load_more_button_title", "Hide \\\'Load More\\\' button"), - StringResource("revanced_hide_load_more_button_summary_on", "Button is hidden"), - StringResource("revanced_hide_load_more_button_summary_off", "Button is shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.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 index 011ec9df00..e69de29bb2 100644 --- 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 @@ -1,54 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.personalinformation - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.youtube.layout.hide.personalinformation.fingerprints.AccountSwitcherAccessibilityLabelFingerprint -import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch -import app.revanced.util.exception -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction - -@Deprecated("This patch is no longer working and will be removed in a future release.") -@Patch( - description = "Hides the email address in the account switcher.", - dependencies = [IntegrationsPatch::class, HideEmailAddressResourcePatch::class], - compatiblePackages = [ - CompatiblePackage( - "com.google.android.youtube", [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" - ] - ) - ] -) -@Suppress("unused") -object HideEmailAddressPatch : BytecodePatch( - setOf(AccountSwitcherAccessibilityLabelFingerprint) -) { - override fun execute(context: BytecodeContext) { - AccountSwitcherAccessibilityLabelFingerprint.result?.let { - it.mutableMethod.apply { - val setVisibilityConstIndex = it.scanResult.patternScanResult!!.endIndex - - val setVisibilityConstRegister = - getInstruction(setVisibilityConstIndex - 2).registerA - - addInstructions( - setVisibilityConstIndex, - """ - invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I - move-result v$setVisibilityConstRegister - """ - ) - } - } ?: throw AccountSwitcherAccessibilityLabelFingerprint.exception - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressResourcePatch.kt deleted file mode 100644 index 3838d0dc42..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/HideEmailAddressResourcePatch.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.personalinformation - -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.misc.settings.SettingsPatch - -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) -@Suppress("unused") -internal object HideEmailAddressResourcePatch : ResourcePatch() { - internal var accountSwitcherAccessibilityLabelId: Long = -1 - - override fun execute(context: ResourceContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_email_address", - StringResource("revanced_hide_email_address_title", "Hide email in account switcher"), - StringResource("revanced_hide_email_address_summary_on", "Email address is hidden"), - StringResource("revanced_hide_email_address_summary_off", "Email address is shown") - ) - ) - - accountSwitcherAccessibilityLabelId = ResourceMappingPatch.resourceMappings.single { - it.type == "string" && it.name == "account_switcher_accessibility_label" - }.id - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt deleted file mode 100644 index 6ea89a8df0..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.personalinformation.fingerprints - -import app.revanced.patches.youtube.layout.hide.personalinformation.HideEmailAddressResourcePatch -import app.revanced.util.patch.LiteralValueFingerprint -import com.android.tools.smali.dexlib2.Opcode - -internal object AccountSwitcherAccessibilityLabelFingerprint : LiteralValueFingerprint( - returnType = "V", - parameters = listOf("L", "Ljava/lang/Object;"), - opcodes = listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.NEW_ARRAY, - Opcode.CONST_4, - Opcode.APUT_OBJECT, - Opcode.CONST, - ), - literalSupplier = { HideEmailAddressResourcePatch.accountSwitcherAccessibilityLabelId } -) \ No newline at end of file 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 ceea41f63b..4449fed857 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 @@ -4,31 +4,38 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( name = "Player flyout menu", - description = "Hides player flyout menu items.", + description = "Adds options to hide menu items that appear when pressing the gear icon in the video player.", dependencies = [ LithoFilterPatch::class, PlayerTypeHookPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ - CompatiblePackage("com.google.android.youtube", [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" - ]) + CompatiblePackage( + "com.google.android.youtube", [ + "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" + ] + ) ] ) @Suppress("unused") @@ -36,76 +43,26 @@ object HidePlayerFlyoutMenuPatch : ResourcePatch() { private const val KEY = "revanced_hide_player_flyout" private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/PlayerFlyoutMenuItemsFilter;" + "Lapp/revanced/integrations/youtube/patches/components/PlayerFlyoutMenuItemsFilter;" override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( - KEY, - StringResource("${KEY}_title", "Player flyout menu items"), - listOf( - SwitchPreference( - "${KEY}_captions", - StringResource("${KEY}_captions_title", "Hide Captions menu"), - StringResource("${KEY}_captions_on", "Captions menu item is hidden"), - StringResource("${KEY}_captions_off", "Captions menu item is shown") - ), - SwitchPreference( - "${KEY}_additional_settings", - StringResource("${KEY}_additional_settings_title", "Hide Additional settings menu"), - StringResource("${KEY}_additional_settings_on", "Additional settings menu item is hidden"), - StringResource("${KEY}_additional_settings_off", "Additional settings menu item is shown") - ), - SwitchPreference( - "${KEY}_loop_video", - StringResource("${KEY}_loop_video_title", "Hide Loop video menu"), - StringResource("${KEY}_loop_video_on", "Loop video menu item is hidden"), - StringResource("${KEY}_loop_video_off", "Loop video menu item is shown") - ), - SwitchPreference( - "${KEY}_ambient_mode", - StringResource("${KEY}_ambient_mode_title", "Hide Ambient mode menu"), - StringResource("${KEY}_ambient_mode_on", "Ambient mode menu item is hidden"), - StringResource("${KEY}_ambient_mode_off", "Ambient mode menu item is shown") - ), - SwitchPreference( - "${KEY}_report", - StringResource("${KEY}_report_title", "Hide Report menu"), - StringResource("${KEY}_report_on", "Report menu item is hidden"), - StringResource("${KEY}_report_off", "Report menu item is shown") - ), - SwitchPreference( - "${KEY}_help", - StringResource("${KEY}_help_title", "Hide Help menu"), - StringResource("${KEY}_help_on", "Help menu item is hidden"), - StringResource("${KEY}_help_off", "Help menu item is shown") - ), - SwitchPreference( - "${KEY}_speed", - StringResource("${KEY}_speed_title", "Hide Speed menu"), - StringResource("${KEY}_speed_on", "Speed menu item is hidden"), - StringResource("${KEY}_speed_off", "Speed menu item is shown") - ), - SwitchPreference( - "${KEY}_more_info", - StringResource("${KEY}_more_info_title", "Hide More info menu"), - StringResource("${KEY}_more_info_on", "More info menu item is hidden"), - StringResource("${KEY}_more_info_off", "More info menu item is shown") - ), - SwitchPreference( - "${KEY}_audio_track", - StringResource("${KEY}_audio_track_title", "Hide Audio track menu"), - StringResource("${KEY}_audio_track_on", "Audio track menu item is hidden"), - StringResource("${KEY}_audio_track_off", "Audio track menu item is shown") - ), - SwitchPreference( - "${KEY}_watch_in_vr", - StringResource("${KEY}_watch_in_vr_title", "Hide Watch in VR menu"), - StringResource("${KEY}_watch_in_vr_on", "Watch in VR menu item is hidden"), - StringResource("${KEY}_watch_in_vr_off", "Watch in VR menu item is shown") - ), + key = KEY, + preferences = setOf( + SwitchPreference("${KEY}_captions"), + SwitchPreference("${KEY}_additional_settings"), + SwitchPreference("${KEY}_loop_video"), + SwitchPreference("${KEY}_ambient_mode"), + SwitchPreference("${KEY}_report"), + SwitchPreference("${KEY}_help"), + SwitchPreference("${KEY}_speed"), + SwitchPreference("${KEY}_more_info"), + SwitchPreference("${KEY}_audio_track"), + SwitchPreference("${KEY}_watch_in_vr"), ), - StringResource("${KEY}_summary", "Manage the visibility of player flyout menu items") ) ) 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 43b0d45414..d9cb1c2c4d 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.layout.hide.rollingnumber -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels @@ -9,24 +8,29 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +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 import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Disable rolling number animations", - description = "Disables rolling number animations of video view count, user likes, and upload time.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to disable rolling number animations of video view count, user likes, and upload time.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -38,16 +42,13 @@ object DisableRollingNumberAnimationPatch : BytecodePatch( ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/DisableRollingNumberAnimationsPatch;" + "Lapp/revanced/integrations/youtube/patches/DisableRollingNumberAnimationsPatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_disable_rolling_number_animations", - StringResource("revanced_disable_rolling_number_animations_title", "Disable rolling number animations"), - StringResource("revanced_disable_rolling_number_animations_summary_on", "Rolling numbers are not animated"), - StringResource("revanced_disable_rolling_number_animations_summary_off", "Rolling numbers are animated") - ) + SwitchPreference("revanced_disable_rolling_number_animations") ) // Animations are disabled by preventing an Image from being applied to the text span, 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 3d3c8dc205..92079f3005 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 @@ -5,8 +5,8 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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 @@ -16,12 +16,13 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint @Patch( name = "Hide seekbar", - description = "Hides the seekbar.", + description = "Adds an option to hide the seekbar.", dependencies = [ IntegrationsPatch::class, SettingsPatch::class, SeekbarColorBytecodePatch::class, - SeekbarPreferencesPatch::class + SeekbarPreferencesPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -31,8 +32,12 @@ import app.revanced.patches.youtube.shared.fingerprints.SeekbarOnDrawFingerprint "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -42,19 +47,11 @@ object HideSeekbarPatch : BytecodePatch( setOf(SeekbarFingerprint) ) { override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SeekbarPreferencesPatch.addPreferences( - SwitchPreference( - "revanced_hide_seekbar", - StringResource("revanced_hide_seekbar_title", "Hide seekbar in video player"), - StringResource("revanced_hide_seekbar_summary_on", "Video player seekbar is hidden"), - StringResource("revanced_hide_seekbar_summary_off", "Video player seekbar is shown") - ), - SwitchPreference( - "revanced_hide_seekbar_thumbnail", - StringResource("revanced_hide_seekbar_thumbnail_title", "Hide seekbar in video thumbnails"), - StringResource("revanced_hide_seekbar_thumbnail_summary_on", "Thumbnail seekbar is hidden"), - StringResource("revanced_hide_seekbar_thumbnail_summary_off", "Thumbnail seekbar is shown") - ) + SwitchPreference("revanced_hide_seekbar"), + SwitchPreference("revanced_hide_seekbar_thumbnail") ) SeekbarFingerprint.result!!.let { @@ -63,7 +60,7 @@ object HideSeekbarPatch : BytecodePatch( 0, """ const/4 v0, 0x0 - invoke-static { }, Lapp/revanced/integrations/patches/HideSeekbarPatch;->hideSeekbar()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/HideSeekbarPatch;->hideSeekbar()Z move-result v0 if-eqz v0, :hide_seekbar return-void diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt index e59040085b..46a3d23227 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/HideShortsComponentsPatch.kt @@ -10,7 +10,7 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.youtube.layout.hide.shorts.fingerprints.* import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch @@ -20,7 +20,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Hide Shorts components", - description = "Hides components from YouTube Shorts.", + description = "Adds options to hide components related to YouTube Shorts.", dependencies = [ IntegrationsPatch::class, LithoFilterPatch::class, @@ -35,8 +35,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -51,11 +55,13 @@ object HideShortsComponentsPatch : BytecodePatch( SetPivotBarVisibilityParentFingerprint ) ) { - private const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/ShortsFilter;" + private const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/components/ShortsFilter;" override fun execute(context: BytecodeContext) { // region Hide the Shorts shelf. + // This patch point is not present in 19.03.x and greater. + // If 19.02.x and lower is dropped, then this section of code and the fingerprint should be removed. ReelConstructorFingerprint.result?.let { it.mutableMethod.apply { val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 @@ -68,7 +74,7 @@ object HideShortsComponentsPatch : BytecodePatch( "hideShortsShelf" ) } - } ?: throw ReelConstructorFingerprint.exception + } // Do not throw an exception if not resolved. // endregion 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 51c05873e3..b9f411fea1 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 @@ -3,103 +3,49 @@ package app.revanced.patches.youtube.layout.hide.shorts import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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 -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) +@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class]) object HideShortsComponentsResourcePatch : ResourcePatch() { internal var reelMultipleItemShelfId = -1L internal var reelPlayerRightCellButtonHeight = -1L override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( "revanced_shorts_preference_screen", - StringResource("revanced_shorts_preference_screen_title", "Shorts components"), - listOf( - SwitchPreference( - "revanced_hide_shorts", - StringResource("revanced_hide_shorts_title", "Hide Shorts in feed"), - StringResource("revanced_hide_shorts_on", "Shorts are hidden"), - StringResource("revanced_hide_shorts_off", "Shorts are shown") - ), - SwitchPreference( - "revanced_hide_shorts_join_button", - StringResource("revanced_hide_shorts_join_button_title", "Hide join button"), - StringResource("revanced_hide_shorts_join_button_on", "Join button is hidden"), - StringResource("revanced_hide_shorts_join_button_off", "Join button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_subscribe_button", - StringResource("revanced_hide_shorts_subscribe_button_title", "Hide subscribe button"), - StringResource("revanced_hide_shorts_subscribe_button_on", "Subscribe button is hidden"), - StringResource("revanced_hide_shorts_subscribe_button_off", "Subscribe button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_subscribe_button_paused", - StringResource("revanced_hide_shorts_subscribe_button_paused_title", "Hide subscribe button when paused"), - StringResource("revanced_hide_shorts_subscribe_button_paused_on", "Subscribe button is hidden"), - StringResource("revanced_hide_shorts_subscribe_button_paused_off", "Subscribe button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_thanks_button", - StringResource("revanced_hide_shorts_thanks_button_title", "Hide thanks button"), - StringResource("revanced_hide_shorts_thanks_button_on", "Thanks button is hidden"), - StringResource("revanced_hide_shorts_thanks_button_off", "Thanks button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_comments_button", - StringResource("revanced_hide_shorts_comments_button_title", "Hide comments button"), - StringResource("revanced_hide_shorts_comments_button_on", "Comments button is hidden"), - StringResource("revanced_hide_shorts_comments_button_off", "Comments button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_remix_button", - StringResource("revanced_hide_shorts_remix_button_title", "Hide remix button"), - StringResource("revanced_hide_shorts_remix_button_on", "Remix button is hidden"), - StringResource("revanced_hide_shorts_remix_button_off", "Remix button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_share_button", - StringResource("revanced_hide_shorts_share_button_title", "Hide share button"), - StringResource("revanced_hide_shorts_share_button_on", "Share button is hidden"), - StringResource("revanced_hide_shorts_share_button_off", "Share button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_info_panel", - StringResource("revanced_hide_shorts_info_panel_title", "Hide info panel"), - StringResource("revanced_hide_shorts_info_panel_on", "Info panel is hidden"), - StringResource("revanced_hide_shorts_info_panel_off", "Info panel is shown") - ), - SwitchPreference( - "revanced_hide_shorts_channel_bar", - StringResource("revanced_hide_shorts_channel_bar_title", "Hide channel bar"), - StringResource("revanced_hide_shorts_channel_bar_on", "Channel bar is hidden"), - StringResource("revanced_hide_shorts_channel_bar_off", "Channel bar is shown") - ), - SwitchPreference( - "revanced_hide_shorts_sound_button", - StringResource("revanced_hide_shorts_sound_button_title", "Hide sound button"), - StringResource("revanced_hide_shorts_sound_button_on", "Sound button is hidden"), - StringResource("revanced_hide_shorts_sound_button_off", "Sound button is shown") - ), - SwitchPreference( - "revanced_hide_shorts_navigation_bar", - StringResource("revanced_hide_shorts_navigation_bar_title", "Hide navigation bar"), - StringResource("revanced_hide_shorts_navigation_bar_on", "Navigation bar is hidden"), - StringResource("revanced_hide_shorts_navigation_bar_off", "Navigation bar is shown") - ) - ), - StringResource("revanced_shorts_preference_screen_summary", "Manage the visibility of Shorts components") + 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") + ) ) ) - fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id + ResourceMappingPatch.resourceMappings.find { + it.type == "layout" && it.name == "reel_multiple_items_shelf" + }?.also { + reelMultipleItemShelfId = it.id + } - reelMultipleItemShelfId = "reel_multiple_items_shelf".getId() - reelPlayerRightCellButtonHeight = "reel_player_right_cell_button_height".getId() + reelPlayerRightCellButtonHeight = + ResourceMappingPatch.resourceMappings.single { + it.type == "dimen" && it.name == "reel_player_right_cell_button_height" + }.id } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt index 912aa9704c..dece9b3718 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/fingerprints/ReelConstructorFingerprint.kt @@ -1,13 +1,19 @@ package app.revanced.patches.youtube.layout.hide.shorts.fingerprints import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patches.youtube.layout.hide.shorts.HideShortsComponentsResourcePatch -import app.revanced.util.patch.LiteralValueFingerprint +import app.revanced.util.containsWideLiteralInstructionValue import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -internal object ReelConstructorFingerprint : LiteralValueFingerprint( +internal object ReelConstructorFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, opcodes = listOf(Opcode.INVOKE_VIRTUAL), - literalSupplier = { HideShortsComponentsResourcePatch.reelMultipleItemShelfId } + customFingerprint = { methodDef, _ -> + // Cannot use LiteralValueFingerprint, because the resource id may not be present. + val reelMultipleItemShelfId = HideShortsComponentsResourcePatch.reelMultipleItemShelfId + reelMultipleItemShelfId != -1L + && methodDef.containsWideLiteralInstructionValue(reelMultipleItemShelfId) + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt index b51a02f4f7..a37f381720 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/suggestedvideoendscreen/DisableSuggestedVideoEndScreenPatch.kt @@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @Patch( name = "Disable suggested video end screen", - description = "Disables the suggested video end screen at the end of a video.", + description = "Adds an option to disable the suggested video end screen at the end of videos.", dependencies = [IntegrationsPatch::class, DisableSuggestedVideoEndScreenResourcePatch::class], compatiblePackages = [ CompatiblePackage( @@ -22,8 +22,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -33,7 +37,7 @@ object DisableSuggestedVideoEndScreenPatch : BytecodePatch( setOf(CreateEndScreenViewFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/DisableSuggestedVideoEndScreenPatch;" + "Lapp/revanced/integrations/youtube/patches/DisableSuggestedVideoEndScreenPatch;" override fun execute(context: BytecodeContext) { CreateEndScreenViewFingerprint.result?.let { 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 f43faaee32..b190b321d3 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 @@ -3,37 +3,26 @@ package app.revanced.patches.youtube.layout.hide.suggestedvideoendscreen import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [ SettingsPatch::class, - ResourceMappingPatch::class + ResourceMappingPatch::class, + AddResourcesPatch::class ], ) internal object DisableSuggestedVideoEndScreenResourcePatch : ResourcePatch() { internal var sizeAdjustableLiteAutoNavOverlay: Long = -1 override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_disable_suggested_video_end_screen", - StringResource( - "revanced_disable_suggested_video_end_screen_title", - "Disable suggested video end screen" - ), - StringResource( - "revanced_disable_suggested_video_end_screen_summary_on", - "Suggested videos will be disabled" - ), - StringResource( - "revanced_disable_suggested_video_end_screen_summary_off", - "Suggested videos will be shown" - ), - ) + SwitchPreference("revanced_disable_suggested_video_end_screen") ) sizeAdjustableLiteAutoNavOverlay = ResourceMappingPatch.resourceMappings.single { 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 0712c6cc8c..665f5f67bb 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 @@ -1,31 +1,34 @@ package app.revanced.patches.youtube.layout.hide.time -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.hide.time.fingerprints.TimeCounterFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Hide timestamp", - description = "Hides timestamp in video player.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to hide the timestamp in the bottom left of the video player.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", "18.37.36", "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -35,20 +38,15 @@ object HideTimestampPatch : BytecodePatch( setOf(TimeCounterFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_timestamp", - StringResource("revanced_hide_timestamp_title", "Hide video timestamp"), - StringResource("revanced_hide_timestamp_summary_on", "Timestamp is hidden"), - StringResource("revanced_hide_timestamp_summary_off", "Timestamp is shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_timestamp")) TimeCounterFingerprint.result?.apply { mutableMethod.addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/HideTimestampPatch;->hideTimestamp()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/HideTimestampPatch;->hideTimestamp()Z move-result v0 if-eqz v0, :hide_time return-void 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 f2d8d5ddc0..f4d1acf03a 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 @@ -1,21 +1,21 @@ package app.revanced.patches.youtube.layout.panels.popup -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.panels.popup.fingerprints.EngagementPanelControllerFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Disable player popup panels", - description = "Disables panels (such as live chat) from opening automatically.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to disable panels (such as live chat) from opening automatically.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -24,8 +24,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -35,14 +39,9 @@ object PlayerPopupPanelsPatch : BytecodePatch( setOf(EngagementPanelControllerFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_player_popup_panels", - StringResource("revanced_hide_player_popup_panels_title", "Hide player popup panels"), - StringResource("revanced_hide_player_popup_panels_summary_on", "Player popup panels are hidden"), - StringResource("revanced_hide_player_popup_panels_summary_off", "Player popup panels are shown") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_hide_player_popup_panels")) val engagementPanelControllerMethod = EngagementPanelControllerFingerprint .result?.mutableMethod ?: throw EngagementPanelControllerFingerprint.exception @@ -50,7 +49,7 @@ object PlayerPopupPanelsPatch : BytecodePatch( engagementPanelControllerMethod.addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/DisablePlayerPopupPanelsPatch;->disablePlayerPopupPanels()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/DisablePlayerPopupPanelsPatch;->disablePlayerPopupPanels()Z move-result v0 if-eqz v0, :player_popup_panels if-eqz p4, :player_popup_panels 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 b465b0a881..def4a95e70 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 @@ -9,7 +9,7 @@ import org.w3c.dom.Element @Patch( name = "Remove player controls background", - description = "Removes the background from the video player controls.", + description = "Removes the dark background surrounding the video player controls.", compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -18,8 +18,12 @@ import org.w3c.dom.Element "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ], diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt index 66ce9a7fb7..fd00bf39b3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/overlay/CustomPlayerOverlayOpacityPatch.kt @@ -13,7 +13,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Custom player overlay opacity", - description = "Change the opacity of the player background when player controls are visible.", + description = "Adds an option to change the opacity of the video player background when player controls are visible.", dependencies = [CustomPlayerOverlayOpacityResourcePatch::class], compatiblePackages = [ CompatiblePackage("com.google.android.youtube") @@ -21,7 +21,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction ) @Suppress("unused") object CustomPlayerOverlayOpacityPatch : BytecodePatch(setOf(CreatePlayerOverviewFingerprint)) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/CustomPlayerOverlayOpacityPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/CustomPlayerOverlayOpacityPatch;" override fun execute(context: BytecodeContext) { CreatePlayerOverviewFingerprint.result?.let { result -> 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 78649a6ae4..a409030c4b 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 @@ -3,32 +3,23 @@ package app.revanced.patches.youtube.layout.player.overlay import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.TextPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +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.TextPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( - dependencies = [SettingsPatch::class, ResourceMappingPatch::class] + dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class] ) internal object CustomPlayerOverlayOpacityResourcePatch : ResourcePatch() { internal var scrimOverlayId = -1L override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - TextPreference( - "revanced_player_overlay_opacity", - StringResource( - "revanced_player_overlay_opacity_title", - "Player overlay opacity" - ), - StringResource( - "revanced_player_overlay_opacity_summary", - "Opacity value between 0-100, where 0 is transparent" - ), - InputType.NUMBER - ) + TextPreference("revanced_player_overlay_opacity", inputType = InputType.NUMBER) ) scrimOverlayId = ResourceMappingPatch.resourceMappings.single { diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt index ef19a1c123..f3f69f10ef 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/ReturnYouTubeDislikePatch.kt @@ -1,33 +1,49 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike -import app.revanced.util.exception -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction -import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.* +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.ConversionContextFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikeFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikesOldLayoutTextViewFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.LikeFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RemoveLikeFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureAnimatedTextFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureStaticLabelFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberMeasureStaticLabelParentFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberSetterFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RollingNumberTextViewFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.ShortsTextViewFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentConstructorFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentDataFingerprint +import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentLookupFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.shared.fingerprints.RollingNumberTextViewAnimationUpdateFingerprint import app.revanced.patches.youtube.video.videoid.VideoIdPatch +import app.revanced.util.exception +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import com.android.tools.smali.dexlib2.Opcode 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 import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference +import com.android.tools.smali.dexlib2.iface.reference.TypeReference @Patch( name = "Return YouTube Dislike", - description = "Shows the dislike count of videos using the Return YouTube Dislike API.", + description = "Adds an option to show the dislike count of videos using the Return YouTube Dislike API.", dependencies = [ IntegrationsPatch::class, LithoFilterPatch::class, @@ -38,10 +54,10 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -49,23 +65,28 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Suppress("unused") object ReturnYouTubeDislikePatch : BytecodePatch( setOf( + ConversionContextFingerprint, TextComponentConstructorFingerprint, + TextComponentDataFingerprint, ShortsTextViewFingerprint, DislikesOldLayoutTextViewFingerprint, LikeFingerprint, DislikeFingerprint, RemoveLikeFingerprint, RollingNumberSetterFingerprint, - RollingNumberMeasureTextParentFingerprint, + RollingNumberMeasureStaticLabelParentFingerprint, + RollingNumberMeasureAnimatedTextFingerprint, RollingNumberTextViewFingerprint, RollingNumberTextViewAnimationUpdateFingerprint ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;" + "Lapp/revanced/integrations/youtube/patches/ReturnYouTubeDislikePatch;" private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch;" + "Lapp/revanced/integrations/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;" + + private fun MethodFingerprint.resultOrThrow() = result ?: throw exception override fun execute(context: BytecodeContext) { // region Inject newVideoLoaded event handler to update dislikes when a new video is loaded. @@ -97,64 +118,132 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // endregion - // region Hook creation of Spans and the cached lookup of them. + // region Hook code for creation and cached lookup of text Spans. // Alternatively the hook can be made at the creation of Spans in TextComponentSpec, // And it works in all situations except it fails to update the Span when the user dislikes, // since the underlying (likes only) text did not change. // This hook handles all situations, as it's where the created Spans are stored and later reused. - TextComponentContextFingerprint.also { - if (!it.resolve(context, TextComponentConstructorFingerprint.result!!.classDef)) - throw it.exception - }.result?.also { result -> - if (!TextComponentAtomicReferenceFingerprint.resolve(context, result.method, result.classDef)) - throw TextComponentAtomicReferenceFingerprint.exception - }?.let { textComponentContextFingerprintResult -> - val conversionContextIndex = textComponentContextFingerprintResult - .scanResult.patternScanResult!!.endIndex - val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!! - .scanResult.patternScanResult!!.startIndex - - val insertIndex = atomicReferenceStartIndex + 9 - - textComponentContextFingerprintResult.mutableMethod.apply { - // Get the conversion context obfuscated field name - val conversionContextFieldReference = - getInstruction(conversionContextIndex).reference - - // Free register to hold the conversion context - val freeRegister = - getInstruction(atomicReferenceStartIndex).registerB - - val atomicReferenceRegister = - getInstruction(atomicReferenceStartIndex + 6).registerC - - // Instruction that is replaced, and also has the CharacterSequence register. - val moveCharSequenceInstruction = getInstruction(insertIndex) - val charSequenceSourceRegister = moveCharSequenceInstruction.registerB - val charSequenceTargetRegister = moveCharSequenceInstruction.registerA - - // Move the current instance to the free register, and get the conversion context from it. - // Must replace the instruction to preserve the control flow label. - replaceInstruction(insertIndex, "move-object/from16 v$freeRegister, p0") + TextComponentConstructorFingerprint.result?.let { textConstructorResult -> + // Find the field name of the conversion context. + val conversionContextClassType = ConversionContextFingerprint.resultOrThrow().classDef.type + val conversionContextField = textConstructorResult.classDef.fields.find { + it.type == conversionContextClassType + } ?: throw PatchException("Could not find conversion context field") + + TextComponentLookupFingerprint.resolve(context, textConstructorResult.classDef) + TextComponentLookupFingerprint.resultOrThrow().mutableMethod.apply { + // Find the instruction for creating the text data object. + val textDataClassType = TextComponentDataFingerprint.resultOrThrow().classDef.type + val insertIndex = indexOfFirstInstruction { + opcode == Opcode.NEW_INSTANCE && + getReference()?.type == textDataClassType + } + if (insertIndex < 0) throw PatchException("Could not find data creation instruction") + val tempRegister = getInstruction(insertIndex).registerA + + // Find the instruction that sets the span to an instance field. + // The instruction is only a few lines after the creation of the instance. + // The method has multiple iput-object instructions using a CharSequence, + // so verify the found instruction is in the expected location. + val putFieldInstruction = implementation!!.instructions + .subList(insertIndex, insertIndex + 20) + .find { + it.opcode == Opcode.IPUT_OBJECT && + it.getReference()?.type == "Ljava/lang/CharSequence;" + } ?: throw PatchException("Could not find put object instruction") + val charSequenceRegister = (putFieldInstruction as TwoRegisterInstruction).registerA + addInstructions( - insertIndex + 1, + insertIndex, """ - # Move context to free register - iget-object v$freeRegister, v$freeRegister, $conversionContextFieldReference - invoke-static {v$freeRegister, v$atomicReferenceRegister, v$charSequenceSourceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; - move-result-object v$freeRegister - # Replace the original instruction - move-object v${charSequenceTargetRegister}, v${freeRegister} + # Copy conversion context + move-object/from16 v$tempRegister, p0 + iget-object v$tempRegister, v$tempRegister, $conversionContextField + invoke-static {v$tempRegister, v$charSequenceRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onLithoTextLoaded(Ljava/lang/Object;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + move-result-object v$charSequenceRegister + """ + ) + } + } ?: throw TextComponentConstructorFingerprint.exception + + // endregion + + // region Hook for non-litho Short videos. + + ShortsTextViewFingerprint.result?.let { + it.mutableMethod.apply { + val patternResult = it.scanResult.patternScanResult!! + + // If the field is true, the TextView is for a dislike button. + val isDisLikesBooleanReference = getInstruction(patternResult.endIndex).reference + + val textViewFieldReference = // Like/Dislike button TextView field + getInstruction(patternResult.endIndex - 1).reference + + // Check if the hooked TextView object is that of the dislike button. + // If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted. + // Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward. + val insertIndex = patternResult.startIndex + 6 + addInstructionsWithLabels( + insertIndex, + """ + # Check, if the TextView is for a dislike button + iget-boolean v0, p0, $isDisLikesBooleanReference + if-eqz v0, :is_like + + # Hook the TextView, if it is for the dislike button + iget-object v0, p0, $textViewFieldReference + invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setShortsDislikes(Landroid/view/View;)Z + move-result v0 + if-eqz v0, :ryd_disabled + return-void + + :is_like + :ryd_disabled + nop """ ) } - } ?: throw TextComponentContextFingerprint.exception + } ?: throw ShortsTextViewFingerprint.exception // endregion + // region Hook for litho Shorts + + // Filter that parses the video id from the UI + LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) + + // Player response video id is needed to search for the video ids in Shorts litho components. + VideoIdPatch.hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V") + + // endregion + + // region Hook old UI layout dislikes, for the older app spoofs used with spoof-app-version. + + DislikesOldLayoutTextViewFingerprint.result?.let { + it.mutableMethod.apply { + val startIndex = it.scanResult.patternScanResult!!.startIndex + + val resourceIdentifierRegister = getInstruction(startIndex).registerA + val textViewRegister = getInstruction(startIndex + 4).registerA + + addInstruction( + startIndex + 4, + "invoke-static {v$resourceIdentifierRegister, v$textViewRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setOldUILayoutDislikes(ILandroid/widget/TextView;)V" + ) + } + } ?: throw DislikesOldLayoutTextViewFingerprint.exception + + // endregion + + // region Hook rolling numbers. + // Do this last to allow patching old unsupported versions (if the user really wants), + // On older unsupported version this will fail to resolve and throw an exception, + // but everything will still work correctly anyways. + RollingNumberSetterFingerprint.result?.let { val dislikesIndex = it.scanResult.patternScanResult!!.endIndex @@ -164,7 +253,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( val charSequenceInstanceRegister = getInstruction(0).registerA val charSequenceFieldReference = - getInstruction(dislikesIndex).reference.toString() + getInstruction(dislikesIndex).reference val registerCount = implementation!!.registerCount @@ -186,37 +275,30 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // Rolling Number text views use the measured width of the raw string for layout. // Modify the measure text calculation to include the left drawable separator if needed. - RollingNumberMeasureAnimatedTextFingerprint.also { - if (!it.resolve(context, RollingNumberMeasureTextParentFingerprint.result!!.classDef)) - throw it.exception - }.result?.also { + RollingNumberMeasureAnimatedTextFingerprint.result?.also { + val scanResult = it.scanResult.patternScanResult!! + // Additional check to verify the opcodes are at the start of the method + if (scanResult.startIndex != 0) throw PatchException("Unexpected opcode location") + val endIndex = scanResult.endIndex it.mutableMethod.apply { - val returnInstructionIndex = it.scanResult.patternScanResult!!.endIndex - val measuredTextWidthRegister = - getInstruction(returnInstructionIndex).registerA + val measuredTextWidthRegister = getInstruction(endIndex).registerA - replaceInstruction( // Replace instruction to preserve control flow label. - returnInstructionIndex, - "invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F" - ) addInstructions( - returnInstructionIndex + 1, - """ - move-result v$measuredTextWidthRegister - return v$measuredTextWidthRegister + endIndex + 1, """ + invoke-static {p1, v$measuredTextWidthRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberMeasured(Ljava/lang/String;F)F + move-result v$measuredTextWidthRegister + """ ) } } ?: throw RollingNumberMeasureAnimatedTextFingerprint.exception // Additional text measurement method. Used if YouTube decides not to animate the likes count // and sometimes used for initial video load. - RollingNumberMeasureStaticLabelFingerprint.also { - if (!it.resolve(context, RollingNumberMeasureTextParentFingerprint.result!!.classDef)) - throw it.exception - }.result?.also { + RollingNumberMeasureStaticLabelFingerprint.resolve(context, RollingNumberMeasureStaticLabelParentFingerprint.resultOrThrow().classDef) + RollingNumberMeasureStaticLabelFingerprint.result?.also { + val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1 it.mutableMethod.apply { - val measureTextIndex = it.scanResult.patternScanResult!!.startIndex + 1 val freeRegister = getInstruction(0).registerA addInstructions( @@ -268,73 +350,6 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // endregion - // region Hook for non-litho Short videos. - - ShortsTextViewFingerprint.result?.let { - it.mutableMethod.apply { - val patternResult = it.scanResult.patternScanResult!! - - // If the field is true, the TextView is for a dislike button. - val isDisLikesBooleanReference = getInstruction(patternResult.endIndex).reference - - val textViewFieldReference = // Like/Dislike button TextView field - getInstruction(patternResult.endIndex - 1).reference - - // Check if the hooked TextView object is that of the dislike button. - // If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted. - // Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward. - val insertIndex = patternResult.startIndex + 6 - addInstructionsWithLabels( - insertIndex, - """ - # Check, if the TextView is for a dislike button - iget-boolean v0, p0, $isDisLikesBooleanReference - if-eqz v0, :is_like - - # Hook the TextView, if it is for the dislike button - iget-object v0, p0, $textViewFieldReference - invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setShortsDislikes(Landroid/view/View;)Z - move-result v0 - if-eqz v0, :ryd_disabled - return-void - - :is_like - :ryd_disabled - nop - """ - ) - } - } ?: throw ShortsTextViewFingerprint.exception - - // endregion - - // region Hook for litho Shorts - - // Filter that parses the video id from the UI - LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) - - // Player response video id is needed to search for the video ids in Shorts litho components. - VideoIdPatch.hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V") - - // endregion - - // region Hook old UI layout dislikes, for the older app spoofs used with spoof-app-version. - - DislikesOldLayoutTextViewFingerprint.result?.let { - it.mutableMethod.apply { - val startIndex = it.scanResult.patternScanResult!!.startIndex - - val resourceIdentifierRegister = getInstruction(startIndex).registerA - val textViewRegister = getInstruction(startIndex + 4).registerA - - addInstruction( - startIndex + 4, - "invoke-static {v$resourceIdentifierRegister, v$textViewRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setOldUILayoutDislikes(ILandroid/widget/TextView;)V" - ) - } - } ?: throw DislikesOldLayoutTextViewFingerprint.exception - - // endregion } private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) 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 de38d67141..848b86af6e 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 @@ -3,28 +3,31 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.StringResource +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.util.mergeStrings @Patch( - dependencies = [SettingsPatch::class] + dependencies = [ + SettingsPatch::class, + AddResourcesPatch::class + ] ) internal object ReturnYouTubeDislikeResourcePatch : ResourcePatch() { internal var oldUIDislikeId: Long = -1 override fun execute(context: ResourceContext) { - SettingsPatch.addPreference( - Preference( - StringResource("revanced_ryd_settings_title", "Return YouTube Dislike"), - StringResource("revanced_ryd_settings_summary", "Settings for Return YouTube Dislike"), - SettingsPatch.createReVancedSettingsIntent("ryd_settings") + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + IntentPreference( + "revanced_ryd_settings", + intent = SettingsPatch.newIntent("revanced_ryd_settings_intent") ) ) - // merge strings - context.mergeStrings("returnyoutubedislike/host/values/strings.xml") + + AddResourcesPatch(this::class) oldUIDislikeId = ResourceMappingPatch.resourceMappings.single { it.type == "id" && it.name == "dislike_button" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt new file mode 100644 index 0000000000..75b6eb55cc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ConversionContextFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object ConversionContextFingerprint : MethodFingerprint( + returnType = "Ljava/lang/String;", + parameters = listOf(), + strings = listOf( + ", widthConstraint=", + ", heightConstraint=", + ", templateLoggerFactory=", + ", rootDisposableContainer=", + // 18.37.36 and after this String is: ConversionContext{containerInternal= + // and before it is: ConversionContext{container= + // Use a partial string to match both. + "ConversionContext{container" + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureAnimatedTextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureAnimatedTextFingerprint.kt index 717131ff59..69d0168129 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureAnimatedTextFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureAnimatedTextFingerprint.kt @@ -5,19 +5,24 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -/** - * Resolves to class found in [RollingNumberMeasureTextParentFingerprint]. - */ internal object RollingNumberMeasureAnimatedTextFingerprint : MethodFingerprint( - returnType = "F", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Ljava/lang/String;"), + returnType = "Lj\$/util/Optional;", + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + parameters = listOf( + "L", + "Ljava/lang/String;", + "L" + ), opcodes = listOf( - Opcode.INVOKE_VIRTUAL, + Opcode.IGET, // First instruction of method + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CONST_HIGH16, + Opcode.INVOKE_STATIC, Opcode.MOVE_RESULT, - Opcode.ADD_FLOAT_2ADDR, - Opcode.ADD_INT_LIT8, - Opcode.GOTO, - Opcode.RETURN + Opcode.CONST_4, + Opcode.AGET, + Opcode.CONST_4, + Opcode.CONST_4, // Measured text width ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelFingerprint.kt index 612b711d7d..d16b580b4b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelFingerprint.kt @@ -6,7 +6,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode /** - * Resolves to class found in [RollingNumberMeasureTextParentFingerprint]. + * Resolves to class found in [RollingNumberMeasureStaticLabelParentFingerprint]. */ internal object RollingNumberMeasureStaticLabelFingerprint : MethodFingerprint( returnType = "F", diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureTextParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelParentFingerprint.kt similarity index 82% rename from src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureTextParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelParentFingerprint.kt index 319605bebf..aa5229e996 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureTextParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberMeasureStaticLabelParentFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal object RollingNumberMeasureTextParentFingerprint : MethodFingerprint( +internal object RollingNumberMeasureStaticLabelParentFingerprint : MethodFingerprint( returnType = "Ljava/lang/String;", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf(), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt deleted file mode 100644 index 6a852c9f57..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentAtomicReferenceFingerprint.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.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 - -/** - * Resolves against the same method that [TextComponentContextFingerprint] resolves to. - */ -internal object TextComponentAtomicReferenceFingerprint : MethodFingerprint( - returnType = "L", - accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, - parameters = listOf("L"), - opcodes = listOf( - Opcode.MOVE_OBJECT, // Register B is free register - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - null, - Opcode.INVOKE_VIRTUAL, // Register C is atomic reference - Opcode.MOVE_RESULT_OBJECT, // Register A is char sequence - Opcode.CHECK_CAST, - Opcode.MOVE_OBJECT, // Replace this instruction with patch code - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.GOTO - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt index deb485b1aa..1b82d14b5e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints - import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt deleted file mode 100644 index 3377a37112..0000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentContextFingerprint.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.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 - -/** - * Resolves against the same class that [TextComponentConstructorFingerprint] resolves to. - */ -internal object TextComponentContextFingerprint : MethodFingerprint( - returnType = "L", - accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, - parameters = listOf("L"), - opcodes = listOf( - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.INVOKE_STATIC_RANGE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, // conversion context field name - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt new file mode 100644 index 0000000000..2d70664030 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentDataFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +internal object TextComponentDataFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + parameters = listOf("L", "L"), + strings = listOf("text"), + customFingerprint = { _, classDef -> + val fields = classDef.fields + fields.find { it.type == "Ljava/util/BitSet;" } != null && + fields.find { it.type == "[Ljava/lang/String;" } != null + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentLookupFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentLookupFingerprint.kt new file mode 100644 index 0000000000..b6b175ac09 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentLookupFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + +/** + * Resolves against the same class that [TextComponentConstructorFingerprint] resolves to. + */ +internal object TextComponentLookupFingerprint : MethodFingerprint( + returnType = "L", + accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("L"), + strings = listOf("…") +) \ No newline at end of file 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 bc25906863..30b979b57d 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.layout.searchbar -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.fingerprint.MethodFingerprint @@ -8,17 +7,18 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.searchbar.fingerprints.CreateSearchSuggestionsFingerprint import app.revanced.patches.youtube.layout.searchbar.fingerprints.SetWordmarkHeaderFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Wide searchbar", - description = "Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -26,8 +26,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.37.36", "18.38.44", "18.43.45", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -40,14 +44,9 @@ object WideSearchbarPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_wide_searchbar", - StringResource("revanced_wide_searchbar_enabled_title", "Enable wide search bar"), - StringResource("revanced_wide_searchbar_summary_on", "Wide search bar is enabled"), - StringResource("revanced_wide_searchbar_summary_off", "Wide search bar is disabled") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_wide_searchbar")) val result = CreateSearchSuggestionsFingerprint.result ?: throw CreateSearchSuggestionsFingerprint.exception @@ -80,7 +79,7 @@ object WideSearchbarPatch : BytecodePatch( addInstructions( implementation!!.instructions.size - 1, """ - invoke-static {}, Lapp/revanced/integrations/patches/WideSearchbarPatch;->enableWideSearchbar()Z + invoke-static {}, Lapp/revanced/integrations/youtube/patches/WideSearchbarPatch;->enableWideSearchbar()Z move-result p0 """ ) 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 bebf677cf1..a8f5932d6d 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 @@ -1,22 +1,21 @@ package app.revanced.patches.youtube.layout.seekbar -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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 = "Restores the old seekbar thumbnails that appear above the seekbar instead of fullscreen thumbnails.", - dependencies = [IntegrationsPatch::class, SeekbarPreferencesPatch::class], + 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], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -24,8 +23,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -35,26 +38,12 @@ object RestoreOldSeekbarThumbnailsPatch : BytecodePatch( setOf(FullscreenSeekbarThumbnailsFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/RestoreOldSeekbarThumbnailsPatch;" + "Lapp/revanced/integrations/youtube/patches/RestoreOldSeekbarThumbnailsPatch;" override fun execute(context: BytecodeContext) { - SeekbarPreferencesPatch.addPreferences( - SwitchPreference( - "revanced_restore_old_seekbar_thumbnails", - StringResource( - "revanced_restore_old_seekbar_thumbnails_title", - "Restore old seekbar thumbnails" - ), - StringResource( - "revanced_restore_old_seekbar_thumbnails_summary_on", - "Seekbar thumbnails will appear above the seekbar" - ), - StringResource( - "revanced_restore_old_seekbar_thumbnails_summary_off", - "Seekbar thumbnails will appear in fullscreen" - ), - ) - ) + AddResourcesPatch(this::class) + + SeekbarPreferencesPatch.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/SeekbarColorBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt index 84aae5b8ab..98acf716c5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarColorBytecodePatch.kt @@ -26,7 +26,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction internal object SeekbarColorBytecodePatch : BytecodePatch( setOf(PlayerSeekbarColorFingerprint, ShortsSeekbarColorFingerprint, SetSeekbarClickedColorFingerprint) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/SeekbarColorPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/theme/SeekbarColorPatch;" override fun execute(context: BytecodeContext) { fun MutableMethod.addColorChangeInstructions(resourceId: Long) { 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 ae968743c2..5c7d6272a6 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 @@ -4,7 +4,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.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import org.w3c.dom.Element @@ -38,7 +38,7 @@ internal object SeekbarColorResourcePatch : ResourcePatch(){ 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.patches.theme.ProgressBarDrawable") + "app.revanced.integrations.youtube.patches.theme.ProgressBarDrawable") scaleNode.replaceChild(replacementNode, shapeNode) } } 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 index dcdf6f672a..0a9f7e27db 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarPreferencesPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/SeekbarPreferencesPatch.kt @@ -3,31 +3,28 @@ 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.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource +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]) +@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class]) internal object SeekbarPreferencesPatch : ResourcePatch(), Closeable { - private val seekbarPreferences = mutableListOf() + 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", - StringResource("revanced_seekbar_preference_screen_title", "Seekbar"), - seekbarPreferences, - StringResource( - "revanced_seekbar_preference_screen_summary", - "Settings for the seekbar" - ) + preferences = seekbarPreferences, ) ) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt index d865f31cd4..e8ce6f193d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/SponsorBlockBytecodePatch.kt @@ -11,7 +11,7 @@ import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.AppendTimeFingerprint import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.ControlsOverlayFingerprint import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.RectangleFieldInvalidatorFingerprint @@ -34,17 +34,15 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference @Patch( name = "SponsorBlock", - description = "Integrates SponsorBlock, which can skip undesired video segments such as sponsored content.", + description = "Adds options to enable and configure SponsorBlock, which can skip undesired video segments such as sponsored content.", compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ], @@ -69,13 +67,13 @@ object SponsorBlockBytecodePatch : BytecodePatch( ) ) { private const val INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/sponsorblock/SegmentPlaybackController;" + "Lapp/revanced/integrations/youtube/sponsorblock/SegmentPlaybackController;" private const val INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/sponsorblock/ui/CreateSegmentButtonController;" + "Lapp/revanced/integrations/youtube/sponsorblock/ui/CreateSegmentButtonController;" private const val INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/sponsorblock/ui/VotingButtonController;" + "Lapp/revanced/integrations/youtube/sponsorblock/ui/VotingButtonController;" private const val INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/sponsorblock/ui/SponsorBlockViewController;" + "Lapp/revanced/integrations/youtube/sponsorblock/ui/SponsorBlockViewController;" override fun execute(context: BytecodeContext) { LayoutConstructorFingerprint.result?.let { 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 c3cb068e20..a8c347b2c7 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 @@ -1,55 +1,52 @@ package app.revanced.patches.youtube.layout.sponsorblock 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.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.StringResource +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.util.ResourceGroup import app.revanced.util.copyResources import app.revanced.util.copyXmlNode -import app.revanced.util.mergeStrings +import app.revanced.util.inputStreamFromBundledResource -@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) +@Patch( + dependencies = [ + SettingsPatch::class, + ResourceMappingPatch::class, + AddResourcesPatch::class + ] +) internal object SponsorBlockResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { - SettingsPatch.addPreference( - Preference( - StringResource("revanced_sponsorblock_settings_title", "SponsorBlock"), - StringResource("revanced_sponsorblock_settings_summary", "SponsorBlock related settings"), - SettingsPatch.createReVancedSettingsIntent("sponsorblock_settings") + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + IntentPreference( + "revanced_sb_settings", + intent = SettingsPatch.newIntent("revanced_sb_settings_intent") ) ) - val classLoader = this.javaClass.classLoader - - /* - merge SponsorBlock strings to main strings - */ - context.mergeStrings("sponsorblock/host/values/strings.xml") - - /* - merge SponsorBlock drawables to main drawables - */ - arrayOf( ResourceGroup( "layout", - "inline_sponsor_overlay.xml", - "new_segment.xml", - "skip_sponsor_button.xml" + "revanced_sb_inline_sponsor_overlay.xml", + "revanced_sb_new_segment.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 "drawable", - "ic_sb_adjust.xml", - "ic_sb_compare.xml", - "ic_sb_edit.xml", - "ic_sb_logo.xml", - "ic_sb_publish.xml", - "ic_sb_voting.xml" + "revanced_sb_adjust.xml", + "revanced_sb_compare.xml", + "revanced_sb_edit.xml", + "revanced_sb_logo.xml", + "revanced_sb_publish.xml", + "revanced_sb_voting.xml" ), ResourceGroup( // required resource for back button, because when the base APK is used, this resource will not exist @@ -59,14 +56,14 @@ internal object SponsorBlockResourcePatch : ResourcePatch() { context.copyResources("sponsorblock", resourceGroup) } - /* - merge xml nodes from the host to their real xml files - */ - // copy nodes from host resources to their real xml files - val hostingResourceStream = - classLoader.getResourceAsStream("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"] "RelativeLayout".copyXmlNode( context.xmlEditor[hostingResourceStream], @@ -82,12 +79,15 @@ internal object SponsorBlockResourcePatch : ResourcePatch() { 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/sb_voting_button" + val votingButtonId = "@+id/revanced_sb_voting_button" view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId + modifiedControlsLayout = true break } - }.close() // close afterwards + }.close() + + 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/spoofappversion/SpoofAppVersionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/SpoofAppVersionPatch.kt index f0892f8bc6..efa71607e9 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 @@ -1,25 +1,24 @@ package app.revanced.patches.youtube.layout.spoofappversion -import app.revanced.util.exception 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.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.spoofappversion.fingerprints.SpoofAppVersionFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Spoof app version", - description = "Tricks YouTube into thinking you are running an older version of the app. " + + 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.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -28,8 +27,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -38,46 +41,17 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction object SpoofAppVersionPatch : BytecodePatch( setOf(SpoofAppVersionFingerprint) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/spoof/SpoofAppVersionPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/youtube/patches/spoof/SpoofAppVersionPatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_spoof_app_version", - StringResource("revanced_spoof_app_version_title", "Spoof app version"), - StringResource("revanced_spoof_app_version_summary_on", "Version spoofed"), - StringResource("revanced_spoof_app_version_summary_off", "Version not spoofed"), - StringResource("revanced_spoof_app_version_user_dialog_message", - "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.") - ), + SwitchPreference("revanced_spoof_app_version"), ListPreference( - "revanced_spoof_app_version_target", - StringResource( - "revanced_spoof_app_version_target_title", - "Spoof app version target" - ), - ArrayResource( - "revanced_spoof_app_version_target_entries", - listOf( - StringResource("revanced_spoof_app_version_target_entry_1", "18.33.40 - Restore RYD Shorts incognito mode"), - StringResource("revanced_spoof_app_version_target_entry_2", "18.20.39 - Restore wide video speed & quality menu"), - StringResource("revanced_spoof_app_version_target_entry_3", "17.08.35 - Restore old UI layout"), - StringResource("revanced_spoof_app_version_target_entry_4", "16.08.35 - Restore explore tab"), - StringResource("revanced_spoof_app_version_target_entry_5", "16.01.35 - Restore old Shorts player"), - ) - ), - ArrayResource( - "revanced_spoof_app_version_target_entry_values", - listOf( - StringResource("revanced_spoof_app_version_target_entry_value_1", "18.33.40"), - StringResource("revanced_spoof_app_version_target_entry_value_2", "18.20.39"), - StringResource("revanced_spoof_app_version_target_entry_value_3", "17.08.35"), - StringResource("revanced_spoof_app_version_target_entry_value_4", "16.08.35"), - StringResource("revanced_spoof_app_version_target_entry_value_5", "16.01.35"), - ) - ) + key = "revanced_spoof_app_version_target", + summaryKey = null, ) ) 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 5e11bf838d..9016385ad6 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 @@ -5,19 +5,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.fingerprints.HomeActivityFingerprint -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.youtube.layout.startpage.fingerprints.StartActivityFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.patches.youtube.shared.fingerprints.HomeActivityFingerprint import app.revanced.util.exception @Patch( name = "Change start page", - description = "Changes the start page of the app.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to set which page the app opens in instead of the homepage.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube" @@ -29,39 +28,15 @@ object ChangeStartPagePatch : BytecodePatch( setOf(HomeActivityFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/ChangeStartPagePatch;" + "Lapp/revanced/integrations/youtube/patches/ChangeStartPagePatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( ListPreference( - "revanced_start_page", - StringResource( - "revanced_start_page_title", - "Set start page" - ), - ArrayResource( - "revanced_start_page_entries", - listOf( - StringResource("revanced_start_page_home_entry_0", "Default"), - StringResource("revanced_start_page_home_entry_1", "Home"), - StringResource("revanced_start_page_search_entry_2", "Search"), - StringResource("revanced_start_page_subscriptions_entry_3", "Subscriptions"), - StringResource("revanced_start_page_explore_entry_4", "Explore"), - StringResource("revanced_start_page_shorts_entry_5", "Shorts"), - ) - ), - ArrayResource( - "revanced_start_page_values", - listOf( - StringResource("revanced_start_page_home_value_0", ""), - StringResource("revanced_start_page_home_value_1", "MAIN"), - StringResource("revanced_start_page_search_value_2", "open.search"), - StringResource("revanced_start_page_subscriptions_value_3", "open.subscriptions"), - StringResource("revanced_start_page_explore_value_4", "open.explore"), - StringResource("revanced_start_page_shorts_value_5", "open.shorts"), - ) - ), - default = "" + 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 0bef8144ba..caef4295b8 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 @@ -1,21 +1,21 @@ package app.revanced.patches.youtube.layout.startupshortsreset -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.startupshortsreset.fingerprints.UserWasInShortsFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Disable resuming Shorts on startup", - description = "Disables resuming the Shorts player on app startup if a Short was last opened.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to disable the Shorts player from resuming on app startup when Shorts were last being watched.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -24,8 +24,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -36,16 +40,13 @@ object DisableResumingShortsOnStartupPatch : BytecodePatch( ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/DisableResumingStartupShortsPlayerPatch;" + "Lapp/revanced/integrations/youtube/patches/DisableResumingStartupShortsPlayerPatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_disable_resuming_shorts_player", - StringResource("revanced_disable_resuming_shorts_player_title", "Disable resuming Shorts player"), - StringResource("revanced_disable_resuming_shorts_player_summary_on", "Shorts player will not resume on app startup"), - StringResource("revanced_disable_resuming_shorts_player_summary_off", "Shorts player will resume on app startup") - ) + SwitchPreference("revanced_disable_resuming_shorts_player") ) UserWasInShortsFingerprint.result?.apply { 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 9b785d668a..10dadae37a 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.layout.tablet -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -9,16 +8,17 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.tablet.fingerprints.GetFormFactorFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Enable tablet layout", - description = "Spoofs the device form factor to a tablet which enables the tablet layout.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to spoof the device form factor to a tablet which enables the tablet layout.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("com.google.android.youtube")] ) @Suppress("unused") @@ -26,15 +26,9 @@ object EnableTabletLayoutPatch : BytecodePatch( setOf(GetFormFactorFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_tablet_layout", - StringResource("revanced_tablet_layout_enabled_title", "Enable tablet layout"), - StringResource("revanced_tablet_layout_summary_on", "Tablet layout is enabled"), - StringResource("revanced_tablet_layout_summary_off", "Tablet layout is disabled"), - StringResource("revanced_tablet_layout_user_dialog_message", "Community posts do not show up on tablet layouts") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_tablet_layout")) GetFormFactorFingerprint.result?.let { it.mutableMethod.apply { @@ -44,7 +38,7 @@ object EnableTabletLayoutPatch : BytecodePatch( addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/EnableTabletLayoutPatch;->enableTabletLayout()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/EnableTabletLayoutPatch;->enableTabletLayout()Z move-result v0 # Free register if-nez v0, :is_large_form_factor """, 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 5a22ce5bdb..bb96c3a630 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.layout.tabletminiplayer -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.fingerprint.MethodFingerprint @@ -9,21 +8,22 @@ import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerDimensionsCalculatorParentFingerprint import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideFingerprint import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideNoContextFingerprint import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Tablet mini player", - description = "Enables the tablet mini player layout.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to enable the tablet mini player layout.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", arrayOf( @@ -32,8 +32,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ) ) ] @@ -47,14 +51,9 @@ object TabletMiniPlayerPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_tablet_miniplayer", - StringResource("revanced_tablet_miniplayer_title", "Enable tablet mini player"), - StringResource("revanced_tablet_miniplayer_summary_on", "Mini player is enabled"), - StringResource("revanced_tablet_miniplayer_summary_off", "Mini player is disabled") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference("revanced_tablet_miniplayer")) // First resolve the fingerprints via the parent fingerprint. MiniPlayerDimensionsCalculatorParentFingerprint.result @@ -120,7 +119,7 @@ object TabletMiniPlayerPatch : BytecodePatch( this.addInstructions( index, """ - invoke-static {v$overrideRegister}, Lapp/revanced/integrations/patches/TabletMiniPlayerOverridePatch;->getTabletMiniPlayerOverride(Z)Z + invoke-static {v$overrideRegister}, Lapp/revanced/integrations/youtube/patches/TabletMiniPlayerOverridePatch;->getTabletMiniPlayerOverride(Z)Z move-result v$overrideRegister """ ) 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 50f7c2bf2b..633efd8bcb 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 @@ -1,7 +1,5 @@ package app.revanced.patches.youtube.layout.theme -import app.revanced.util.exception -import app.revanced.util.indexOfFirstWideLiteralInstructionValue import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -9,23 +7,26 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.theme.fingerprints.UseGradientLoadingScreenFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception +import app.revanced.util.indexOfFirstWideLiteralInstructionValue import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Theme", - description = "Applies a custom theme.", + description = "Adds options for theming and applies a custom background theme (dark background theme defaults to amoled black).", dependencies = [ LithoColorHookPatch::class, SeekbarColorBytecodePatch::class, ThemeResourcePatch::class, IntegrationsPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( @@ -35,8 +36,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -46,7 +51,7 @@ object ThemeBytecodePatch : BytecodePatch( setOf(UseGradientLoadingScreenFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/theme/ThemePatch;" + "Lapp/revanced/integrations/youtube/patches/theme/ThemePatch;" internal const val GRADIENT_LOADING_SCREEN_AB_CONSTANT = 45412406L @@ -91,20 +96,9 @@ object ThemeBytecodePatch : BytecodePatch( ) override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_gradient_loading_screen", - StringResource("revanced_gradient_loading_screen_title", "Enable gradient loading screen"), - StringResource( - "revanced_gradient_loading_screen_summary_on", - "Loading screen will have a gradient background" - ), - StringResource( - "revanced_gradient_loading_screen_summary_off", - "Loading screen will have a solid background" - ), - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.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 f6fc643358..d379514e2e 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 @@ -4,11 +4,11 @@ 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.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.shared.settings.preference.impl.TextPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +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 @@ -16,25 +16,22 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch import org.w3c.dom.Element @Patch( - dependencies = [SettingsPatch::class, ResourceMappingPatch::class, SeekbarPreferencesPatch::class] + dependencies = [ + SettingsPatch::class, + ResourceMappingPatch::class, + SeekbarPreferencesPatch::class, + AddResourcesPatch::class + ] ) internal object ThemeResourcePatch : ResourcePatch() { private const val SPLASH_BACKGROUND_COLOR = "revanced_splash_background_color" override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SeekbarPreferencesPatch.addPreferences( - SwitchPreference( - "revanced_seekbar_custom_color", - StringResource("revanced_seekbar_custom_color_title", "Enable custom seekbar color"), - StringResource("revanced_seekbar_custom_color_summary_on", "Custom seekbar color is shown"), - StringResource("revanced_seekbar_custom_color_summary_off", "Original seekbar color is shown") - ), - TextPreference( - "revanced_seekbar_custom_color_value", - StringResource("revanced_seekbar_custom_color_value_title", "Custom seekbar color"), - StringResource("revanced_seekbar_custom_color_value_summary", "The color of the seekbar"), - InputType.TEXT_CAP_CHARACTERS - ) + SwitchPreference("revanced_seekbar_custom_color"), + TextPreference("revanced_seekbar_custom_color_value", inputType = InputType.TEXT_CAP_CHARACTERS) ) // Edit theme colors via resources. @@ -73,9 +70,10 @@ internal object ThemeResourcePatch : ResourcePatch() { if (darkThemeBackgroundColor != null && lightThemeBackgroundColor != null) { val splashScreenResourceFiles = listOf( "res/drawable/quantum_launchscreen_youtube.xml", - "res/drawable-sw600dp/quantum_launchscreen_youtube.xml") + "res/drawable-sw600dp/quantum_launchscreen_youtube.xml" + ) - splashScreenResourceFiles.forEach editSplashScreen@ { resourceFile -> + splashScreenResourceFiles.forEach editSplashScreen@{ resourceFile -> context.xmlEditor[resourceFile].use { val layerList = it.file.getElementsByTagName("layer-list").item(0) as Element 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 958b8aac3c..075eaa0edd 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 @@ -10,7 +10,8 @@ import app.revanced.patcher.patch.annotation.CompatiblePackage 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.shared.settings.preference.impl.* +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.* 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 @@ -29,8 +30,13 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod @Patch( name = "Alternative thumbnails", - description = "Adds options to replace video thumbnails with still image captures of the video.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class, AlternativeThumbnailsResourcePatch::class], + description = "Adds options to replace video thumbnails using the DeArrow API or image captures from the video.", + dependencies = [ + IntegrationsPatch::class, + SettingsPatch::class, + AlternativeThumbnailsResourcePatch::class, + AddResourcesPatch::class + ], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", @@ -40,8 +46,12 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -55,7 +65,7 @@ object AlternativeThumbnailsPatch : BytecodePatch( ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/AlternativeThumbnailsPatch;" + "Lapp/revanced/integrations/youtube/patches/AlternativeThumbnailsPatch;" private lateinit var loadImageUrlMethod: MutableMethod private var loadImageUrlIndex = 0 @@ -107,114 +117,38 @@ object AlternativeThumbnailsPatch : BytecodePatch( } override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( "revanced_alt_thumbnail_preference_screen", - StringResource("revanced_alt_thumbnail_preference_screen_title", "Alternative thumbnails"), - listOf( + preferences = setOf( NonInteractivePreference( - StringResource("revanced_alt_thumbnail_about_title", "Thumbnails in use"), + "revanced_alt_thumbnail_about", null, // Summary is dynamically updated based on the current settings. - tag = "app.revanced.integrations.settingsmenu.AlternativeThumbnailsStatusPreference" - ), - SwitchPreference( - "revanced_alt_thumbnail_dearrow", - StringResource("revanced_alt_thumbnail_dearrow_title", "Enable DeArrow thumbnails"), - StringResource("revanced_alt_thumbnail_dearrow_summary_on", "Using DeArrow thumbnails"), - StringResource("revanced_alt_thumbnail_dearrow_summary_off", "Not using DeArrow thumbnails") - ), - SwitchPreference( - "revanced_alt_thumbnail_dearrow_connection_toast", - StringResource("revanced_alt_thumbnail_dearrow_connection_toast_title", "Show a toast if API is not available"), - StringResource("revanced_alt_thumbnail_dearrow_connection_toast_summary_on", "Toast is shown if DeArrow is not available"), - StringResource("revanced_alt_thumbnail_dearrow_connection_toast_summary_off", "Toast is not shown if DeArrow is not available") - ), - TextPreference( - "revanced_alt_thumbnail_dearrow_api_url", - StringResource( - "revanced_alt_thumbnail_dearrow_api_url_title", - "DeArrow API endpoint" - ), - StringResource( - "revanced_alt_thumbnail_dearrow_api_url_summary", - "The URL of the DeArrow thumbnail cache endpoint. " + - "Do not change this unless you know what you\\\'re doing" - ), + 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( - StringResource( - "revanced_alt_thumbnail_dearrow_about_title", - "About DeArrow" - ), - StringResource( - "revanced_alt_thumbnail_dearrow_about_summary", - "DeArrow provides crowd-sourced thumbnails for YouTube videos. " + - "These thumbnails are often more relevant than those provided by YouTube. " + - "If enabled, video URLs will be sent to the API server and no other data is sent." - + "\\n\\nTap here to learn more about DeArrow" - ), + "revanced_alt_thumbnail_dearrow_about", // Custom about preference with link to the DeArrow website. - tag = "app.revanced.integrations.settingsmenu.AlternativeThumbnailsAboutDeArrowPreference", + tag = "app.revanced.integrations.youtube.settings.preference.AlternativeThumbnailsAboutDeArrowPreference", selectable = true ), - SwitchPreference( - "revanced_alt_thumbnail_stills", - StringResource("revanced_alt_thumbnail_stills_title", "Enable still video captures"), - StringResource("revanced_alt_thumbnail_stills_summary_on", "Using YouTube still video captures"), - StringResource("revanced_alt_thumbnail_stills_summary_off", "Not using YouTube still video captures") - ), + SwitchPreference("revanced_alt_thumbnail_stills"), ListPreference( "revanced_alt_thumbnail_stills_time", - StringResource("revanced_alt_thumbnail_stills_time_title", "Video time to take the still from"), - ArrayResource( - "revanced_alt_thumbnail_type_entries", - listOf( - StringResource("revanced_alt_thumbnail_stills_time_entry_1", "Beginning of video"), - StringResource("revanced_alt_thumbnail_stills_time_entry_2", "Middle of video"), - StringResource("revanced_alt_thumbnail_stills_time_entry_3", "End of video"), - ) - ), - ArrayResource( - "revanced_alt_thumbnail_stills_time_entry_values", - listOf( - StringResource("revanced_alt_thumbnail_stills_time_entry_value_1", "1"), - StringResource("revanced_alt_thumbnail_stills_time_entry_value_2", "2"), - StringResource("revanced_alt_thumbnail_stills_time_entry_value_3", "3"), - ) - ) - ), - SwitchPreference( - "revanced_alt_thumbnail_stills_fast", - StringResource( - "revanced_alt_thumbnail_stills_fast_title", - "Use fast still captures" - ), - StringResource( - "revanced_alt_thumbnail_stills_fast_summary_on", - "Using medium quality still captures. " + - "Thumbnails will load faster, but live streams, unreleased, " + - "or very old videos may show blank thumbnails" - ), - StringResource( - "revanced_alt_thumbnail_stills_fast_summary_off", - "Using high quality still captures" - ) + summaryKey = null, ), + SwitchPreference("revanced_alt_thumbnail_stills_fast"), NonInteractivePreference( - StringResource( - "revanced_alt_thumbnail_stills_about_title", - "About still video captures" - ), - StringResource( - "revanced_alt_thumbnail_stills_about_summary", - "Still captures are taken from the beginning/middle/end of each video. " + - "These images are built into YouTube and no external API is used" - ), + "revanced_alt_thumbnail_stills_about", // Restore the preference dividers to keep it from looking weird. selectable = true ) - ), - StringResource("revanced_alt_thumbnail_preference_screen_summary", "Video thumbnail settings") + ) ) ) 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 index 080b2beccb..d926b4a4d2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/thumbnails/AlternativeThumbnailsResourcePatch.kt @@ -3,14 +3,17 @@ 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 -import app.revanced.util.mergeStrings @Patch( - dependencies = [SettingsPatch::class] + dependencies = [ + SettingsPatch::class, + AddResourcesPatch::class + ] ) internal object AlternativeThumbnailsResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { - context.mergeStrings("alternativethumbnails/host/values/strings.xml") + AddResourcesPatch(this::class) } -} \ No newline at end of file +} 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 1636a9d65d..66b01d8e4a 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 @@ -1,35 +1,39 @@ package app.revanced.patches.youtube.misc.announcements -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.patches.youtube.shared.fingerprints.WatchWhileActivityFingerprint +import app.revanced.patches.youtube.shared.fingerprints.MainActivityFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode @Patch( name = "Announcements", - description = "Shows ReVanced announcements on startup.", + description = "Adds an option to show announcements from ReVanced on app startup.", compatiblePackages = [CompatiblePackage("com.google.android.youtube")], - dependencies = [SettingsPatch::class] + dependencies = [SettingsPatch::class,AddResourcesPatch::class] ) @Suppress("unused") object AnnouncementsPatch : BytecodePatch( - setOf(WatchWhileActivityFingerprint) + setOf(MainActivityFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/announcements/AnnouncementsPatch;" + "Lapp/revanced/integrations/youtube/patches/announcements/AnnouncementsPatch;" override fun execute(context: BytecodeContext) { - val onCreateMethod = WatchWhileActivityFingerprint.result?.let { + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_announcements")) + + val onCreateMethod = MainActivityFingerprint.result?.let { it.mutableClass.methods.find { method -> method.name == "onCreate" } - } ?: throw WatchWhileActivityFingerprint.exception + } ?: throw MainActivityFingerprint.exception val superCallIndex = onCreateMethod.getInstructions().indexOfFirst { it.opcode == Opcode.INVOKE_SUPER_RANGE } @@ -38,24 +42,5 @@ object AnnouncementsPatch : BytecodePatch( "invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->showAnnouncement(Landroid/app/Activity;)V" ) - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_announcements", - StringResource( - "revanced_announcements_title", - "Show announcements from ReVanced" - ), - StringResource( - "revanced_announcements_summary_on", - "Announcements are shown on startup" - ), StringResource( - "revanced_announcements_summary_off", - "Announcements are not shown on startup" - ), StringResource( - "revanced_announcements_enabled_summary", - "Show announcements on startup" - ), - ) - ) } } 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 293b25b557..472fa4db36 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 @@ -7,8 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatFingerprint import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParentFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch @@ -16,9 +16,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( - name = "Always autorepeat", - description = "Always repeats the playing video again.", - dependencies = [IntegrationsPatch::class], + name = "Always repeat", + description = "Adds an option to always repeat videos when they end.", + dependencies = [IntegrationsPatch::class,AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", @@ -28,8 +28,12 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -39,20 +43,15 @@ object AutoRepeatPatch : BytecodePatch( setOf(AutoRepeatParentFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_auto_repeat", - StringResource("revanced_auto_repeat_title", "Enable auto-repeat"), - StringResource("revanced_auto_repeat_summary_on", "Auto-repeat is enabled"), - StringResource("revanced_auto_repeat_summary_off", "Auto-repeat is disabled") - ) - ) + AddResourcesPatch(this::class) + + 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 ?: throw PatchException("ParentFingerprint did not resolve.") - //this one needs to be called when app/revanced/integrations/patches/AutoRepeatPatch;->shouldAutoRepeat() returns true + //this one needs to be called when app/revanced/integrations/youtube/patches/AutoRepeatPatch;->shouldAutoRepeat() returns true val playMethod = parentResult.mutableMethod AutoRepeatFingerprint.resolve(context, parentResult.classDef) //String is: Laamp;->E()V @@ -65,7 +64,7 @@ object AutoRepeatPatch : BytecodePatch( //Instructions to add to the smali code val instructions = """ - invoke-static {}, Lapp/revanced/integrations/patches/AutoRepeatPatch;->shouldAutoRepeat()Z + invoke-static {}, Lapp/revanced/integrations/youtube/patches/AutoRepeatPatch;->shouldAutoRepeat()Z move-result v0 if-eqz v0, :noautorepeat invoke-virtual {p0}, $methodToCall 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 8898b76eb7..01576ee2cb 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 @@ -4,64 +4,32 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( name = "Enable debugging", - description = "Adds debugging options.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds options for debugging.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("com.google.android.youtube")] ) @Suppress("unused") object DebuggingPatch : ResourcePatch() { override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.MISC.addPreferences( - app.revanced.patches.shared.settings.preference.impl.PreferenceScreen( + PreferenceScreen( "revanced_debug_preference_screen", - StringResource("revanced_debug_preference_screen_title", "Debugging"), - listOf( - SwitchPreference( - "revanced_debug", - StringResource("revanced_debug_title", "Debug logging"), - StringResource("revanced_debug_summary_on", "Debug logs are enabled"), - StringResource("revanced_debug_summary_off", "Debug logs are disabled") - ), - SwitchPreference( - "revanced_debug_protobuffer", - StringResource( - "revanced_debug_protobuffer_title", - "Log protocol buffer" - ), - StringResource("revanced_debug_protobuffer_summary_on", "Debug logs include proto buffer"), - StringResource("revanced_debug_protobuffer_summary_off", "Debug logs do not include proto buffer") - ), - SwitchPreference( - "revanced_debug_stacktrace", - StringResource( - "revanced_debug_stacktrace_title", - "Log stack traces" - ), - StringResource("revanced_debug_stacktrace_summary_on", "Debug logs include stack trace"), - StringResource("revanced_debug_stacktrace_summary_off", "Debug logs do not include stack trace") - ), - SwitchPreference( - "revanced_debug_toast_on_error", - StringResource( - "revanced_debug_toast_on_error_title", - "Show toast on ReVanced error" - ), - StringResource("revanced_debug_toast_on_error_summary_on", "Toast shown if error occurs"), - StringResource("revanced_debug_toast_on_error_summary_off", "Toast not shown if error occurs"), - StringResource("revanced_debug_toast_on_error_user_dialog_message", - "Turning off error toasts hides all ReVanced error notifications." - + "\\n\\nYou will not be notified of any unexpected events." - ) - ), - ), - StringResource("revanced_debug_preference_screen_summary", "Enable or disable debugging options") + preferences = setOf( + SwitchPreference("revanced_debug"), + SwitchPreference("revanced_debug_protobuffer"), + SwitchPreference("revanced_debug_stacktrace"), + 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 974a344d81..4374787d8d 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 @@ -1,22 +1,21 @@ package app.revanced.patches.youtube.misc.dimensions.spoof -import app.revanced.util.exception 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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.dimensions.spoof.fingerprints.DeviceDimensionsModelToStringFingerprint import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception @Patch( name = "Spoof device dimensions", - description = "Spoofs the device dimensions in order to unlock higher video qualities " + - "that may not be available on your device.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to spoof the device dimensions which unlocks higher video qualities if they aren't available on the device.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", @@ -24,27 +23,27 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] ) +@Suppress("unused") object SpoofDeviceDimensionsPatch : BytecodePatch( setOf(DeviceDimensionsModelToStringFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/spoof/SpoofDeviceDimensionsPatch;" + "Lapp/revanced/integrations/youtube/patches/spoof/SpoofDeviceDimensionsPatch;" override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_spoof_device_dimensions", - StringResource("revanced_spoof_device_dimensions_title", "Spoof device dimensions"), - StringResource("revanced_spoof_device_dimensions_summary_on", "Device dimensions spoofed"), - StringResource("revanced_spoof_device_dimensions_summary_off", "Device dimensions not spoofed"), - ) - ) + AddResourcesPatch(this::class) + + 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/backtoexitgesture/FixBackToExitGesturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt index e5c736835c..bdd3d49690 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/FixBackToExitGesturePatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.fingerprint.MethodFingerprint @@ -10,6 +9,7 @@ import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.OnBa import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewScrollingFingerprint import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewTopScrollingFingerprint import app.revanced.patches.youtube.misc.fix.backtoexitgesture.fingerprints.RecyclerViewTopScrollingParentFingerprint +import app.revanced.util.exception @Patch(description = "Fixes the swipe back to exit gesture.") @Suppress("unused") @@ -37,7 +37,7 @@ internal object FixBackToExitGesturePatch : BytecodePatch( methodName = "onScrollingViews" ), OnBackPressedFingerprint to IntegrationsMethod( - "p0", "onBackPressed", "Lcom/google/android/apps/youtube/app/watchwhile/WatchWhileActivity;" + "p0", "onBackPressed", "Landroid/app/Activity;" ) ).forEach { (fingerprint, target) -> fingerprint.injectCall(target) } } @@ -64,6 +64,6 @@ internal object FixBackToExitGesturePatch : BytecodePatch( val register: String = "", val methodName: String, val parameterTypes: String = "" ) { override fun toString() = - "invoke-static {$register}, Lapp/revanced/integrations/patches/FixBackToExitGesturePatch;->$methodName($parameterTypes)V" + "invoke-static {$register}, Lapp/revanced/integrations/youtube/patches/FixBackToExitGesturePatch;->$methodName($parameterTypes)V" } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt index d44ddfe794..282122b84f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt @@ -12,7 +12,9 @@ internal object OnBackPressedFingerprint : MethodFingerprint( Opcode.RETURN_VOID ), customFingerprint = { methodDef, _ -> - methodDef.definingClass.endsWith("WatchWhileActivity;") + (methodDef.definingClass.endsWith("MainActivity;") || + // Old versions of YouTube called this class "WatchWhileActivity" instead. + methodDef.definingClass.endsWith("WatchWhileActivity;")) && methodDef.name == "onBackPressed" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt index 6d330051bb..6a743562aa 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/ClientSpoofPatch.kt @@ -10,22 +10,18 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patches.youtube.misc.fix.playback.fingerprints.UserAgentHeaderBuilderFingerprint import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction - @Patch( name = "Client spoof", - description = "Spoofs the client to allow playback.", + description = "Adds options to spoof the client to allow video playback.", dependencies = [SpoofSignaturePatch::class], compatiblePackages = [ CompatiblePackage( - "com.google.android.youtube", - [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "com.google.android.youtube", [ + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] 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 fda8784877..0bcfcf2742 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.misc.fix.playback -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels @@ -9,14 +8,15 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +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.fix.playback.fingerprints.* 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 com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @@ -27,7 +27,8 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction PlayerTypeHookPatch::class, PlayerResponseMethodHookPatch::class, VideoInformationPatch::class, - SpoofSignatureResourcePatch::class + SpoofSignatureResourcePatch::class, + AddResourcesPatch::class ] ) object SpoofSignaturePatch : BytecodePatch( @@ -43,70 +44,19 @@ object SpoofSignaturePatch : BytecodePatch( ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/spoof/SpoofSignaturePatch;" + "Lapp/revanced/integrations/youtube/patches/spoof/SpoofSignaturePatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.MISC.addPreferences( PreferenceScreen( "revanced_spoof_signature_verification", - StringResource( - "revanced_spoof_signature_verification_title", - "Spoof app signature" + preferences = setOf( + SwitchPreference("revanced_spoof_signature_verification_enabled"), + SwitchPreference("revanced_spoof_signature_in_feed_enabled"), + SwitchPreference("revanced_spoof_storyboard") ), - listOf( - SwitchPreference( - "revanced_spoof_signature_verification_enabled", - StringResource("revanced_spoof_signature_verification_enabled_title", "Spoof app signature"), - StringResource( - "revanced_spoof_signature_verification_enabled_summary_on", - "App signature spoofed\\n\\n" - + "Side effects include:\\n" - + "• Enhanced bitrate is not available\\n" - + "• Videos cannot be downloaded\\n" - + "• No seekbar thumbnails for paid videos" - ), - StringResource( - "revanced_spoof_signature_verification_enabled_summary_off", - "App signature not spoofed\\n\\nVideo playback may not work" - ), - StringResource( - "revanced_spoof_signature_verification_enabled_user_dialog_message", - "Turning off this setting will cause video playback issues." - ) - ), - SwitchPreference( - "revanced_spoof_signature_in_feed_enabled", - StringResource("revanced_spoof_signature_in_feed_enabled_title", "Spoof app signature in feed"), - StringResource( - "revanced_spoof_signature_in_feed_enabled_summary_on", - "App signature spoofed\\n\\n" - + "Side effects include:\\n" - + "• Feed videos are missing subtitles\\n" - + "• Automatically played feed videos will show up in your watch history" - ), - StringResource( - "revanced_spoof_signature_in_feed_enabled_summary_off", - "App signature not spoofed for feed videos\\n\\n" - + "Feed videos will play for less than 1 minute before encountering playback issues" - ) - ), - SwitchPreference( - "revanced_spoof_storyboard", - StringResource("revanced_spoof_storyboard_title", "Spoof storyboard"), - StringResource("revanced_spoof_storyboard_summary_on", "Storyboard spoofed"), - StringResource( - "revanced_spoof_storyboard_summary_off", - "Storyboard not spoofed\\n\\n" - + "Side effects include:\\n" - + "• No ambient mode\\n" - + "• Seekbar thumbnails are hidden" - ) - ) - ), - StringResource( - "revanced_spoof_signature_verification_summary", - "Spoof the app signature to prevent playback issues" - ) ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt index 884d1237bc..54bfa75406 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.fix.playback import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt index 7d1a11e33e..ff73df5a02 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportPatch.kt @@ -1,20 +1,19 @@ package app.revanced.patches.youtube.misc.gms -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patches.shared.fingerprints.HomeActivityFingerprint -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportPatch +import app.revanced.patches.shared.fingerprints.CastContextFetchFingerprint +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportPatch import app.revanced.patches.youtube.layout.buttons.cast.HideCastButtonPatch import app.revanced.patches.youtube.misc.fix.playback.ClientSpoofPatch import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.gms.GmsCoreSupportResourcePatch.gmsCoreVendorOption import app.revanced.patches.youtube.misc.gms.fingerprints.* -import app.revanced.util.exception +import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch +import app.revanced.patches.youtube.shared.fingerprints.HomeActivityFingerprint @Suppress("unused") -object GmsCoreSupportPatch : AbstractGmsCoreSupportPatch( +object GmsCoreSupportPatch : BaseGmsCoreSupportPatch( fromPackageName = YOUTUBE_PACKAGE_NAME, toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME, primeMethodFingerprint = PrimeMethodFingerprint, @@ -25,21 +24,21 @@ object GmsCoreSupportPatch : AbstractGmsCoreSupportPatch( CastDynamiteModuleV2Fingerprint, CastContextFetchFingerprint ), + mainActivityOnCreateFingerprint = HomeActivityFingerprint, + integrationsPatchDependency = IntegrationsPatch::class, dependencies = setOf( HideCastButtonPatch::class, ClientSpoofPatch::class ), - abstractGmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch, + gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch, compatiblePackages = setOf( CompatiblePackage( "com.google.android.youtube", setOf( - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ) ) ), @@ -50,18 +49,7 @@ object GmsCoreSupportPatch : AbstractGmsCoreSupportPatch( CastDynamiteModuleV2Fingerprint, CastContextFetchFingerprint, PrimeMethodFingerprint, - HomeActivityFingerprint, ) ) { override val gmsCoreVendor by gmsCoreVendorOption - - override fun execute(context: BytecodeContext) { - // Check the availability of GmsCore. - HomeActivityFingerprint.result?.mutableMethod?.addInstruction( - 0, - "invoke-static {}, Lapp/revanced/integrations/patches/GmsCoreSupport;->checkAvailability()V" - ) ?: throw HomeActivityFingerprint.exception - - super.execute(context) - } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportResourcePatch.kt index 8482704d2a..151e1b6c60 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/gms/GmsCoreSupportResourcePatch.kt @@ -1,33 +1,32 @@ package app.revanced.patches.youtube.misc.gms import app.revanced.patcher.data.ResourceContext -import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch -import app.revanced.patches.shared.misc.gms.AbstractGmsCoreSupportResourcePatch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.gms.BaseGmsCoreSupportResourcePatch +import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.patches.youtube.misc.gms.Constants.REVANCED_YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.gms.Constants.YOUTUBE_PACKAGE_NAME import app.revanced.patches.youtube.misc.settings.SettingsPatch -object GmsCoreSupportResourcePatch : AbstractGmsCoreSupportResourcePatch( +object GmsCoreSupportResourcePatch : BaseGmsCoreSupportResourcePatch( fromPackageName = YOUTUBE_PACKAGE_NAME, toPackageName = REVANCED_YOUTUBE_PACKAGE_NAME, spoofedPackageSignature = "24bb24c05e47e0aefa68a58a766179d9b613a600", - dependencies = setOf(SettingsPatch::class) + dependencies = setOf(SettingsPatch::class, AddResourcesPatch::class) ) { override fun execute(context: ResourceContext) { - SettingsPatch.addPreference( - Preference( - StringResource("microg_settings", "GmsCore Settings"), - StringResource("microg_settings_summary", "Settings for GmsCore"), - Preference.Intent("$gmsCoreVendor.android.gms", "", "org.microg.gms.ui.SettingsActivity") + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences( + IntentPreference( + "microg_settings", + intent = IntentPreference.Intent("", "org.microg.gms.ui.SettingsActivity") { + "$gmsCoreVendor.android.gms" + } ) ) - val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(REVANCED_YOUTUBE_PACKAGE_NAME) - SettingsPatch.renameIntentsTargetPackage(packageName) - super.execute(context) } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt index aa21e11010..ed161b2540 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/IntegrationsPatch.kt @@ -1,12 +1,11 @@ package app.revanced.patches.youtube.misc.integrations import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch import app.revanced.patches.youtube.misc.integrations.fingerprints.* @Patch(requiresIntegrations = true) -object IntegrationsPatch : AbstractIntegrationsPatch( - "Lapp/revanced/integrations/utils/ReVancedUtils;", +object IntegrationsPatch : BaseIntegrationsPatch( setOf( ApplicationInitFingerprint, StandalonePlayerActivityFingerprint, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt index 5249509177..ca4ad846e6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/APIPlayerServiceFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint import com.android.tools.smali.dexlib2.AccessFlags /** diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ApplicationInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ApplicationInitFingerprint.kt index 346fb9168f..0cc958cb8c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ApplicationInitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ApplicationInitFingerprint.kt @@ -1,6 +1,6 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint /** * Hooks the context when the app is launched as a regular application (and is not an embedded video playback). diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt index 65b7d08977..1b57540675 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint import com.android.tools.smali.dexlib2.AccessFlags /** diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt index 0e6ddaf6bd..fbc2ab0dbf 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint import com.android.tools.smali.dexlib2.AccessFlags /** diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt index 4079d7e3c5..77eeec32dc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbedFragmentFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint import com.android.tools.smali.dexlib2.AccessFlags /** diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt index 6b3961d547..196994f49b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/RemoteEmbeddedPlayerFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint import com.android.tools.smali.dexlib2.AccessFlags /** diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt index dbe1d9bc01..9148f5fdb5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerActivityFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.shared.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.patches.shared.misc.integrations.BaseIntegrationsPatch.IntegrationsFingerprint import com.android.tools.smali.dexlib2.AccessFlags /** 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 143d595417..663c72fdd3 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 @@ -1,48 +1,48 @@ package app.revanced.patches.youtube.misc.links -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.links.fingerprints.ABUriParserFingerprint import app.revanced.patches.youtube.misc.links.fingerprints.HTTPUriParserFingerprint import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @Patch( name = "Bypass URL redirects", - description = "Bypass URL redirects and open the original URL directly.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to bypass URL redirects and open the original URL directly.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] ) +@Suppress("unused") object BypassURLRedirectsPatch : BytecodePatch( setOf(ABUriParserFingerprint, HTTPUriParserFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_bypass_url_redirects", - StringResource("revanced_bypass_url_redirects_title", "Bypass URL redirects"), - StringResource("revanced_bypass_url_redirects_summary_on", "URL redirects are bypassed"), - StringResource("revanced_bypass_url_redirects_summary_off", "URL redirects are not bypassed"), - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_bypass_url_redirects" )) mapOf( ABUriParserFingerprint to 7, // Offset to Uri.parse. @@ -57,7 +57,7 @@ object BypassURLRedirectsPatch : BytecodePatch( replaceInstruction( insertIndex, "invoke-static {v$uriStringRegister}," + - "Lapp/revanced/integrations/patches/BypassURLRedirectsPatch;" + + "Lapp/revanced/integrations/youtube/patches/BypassURLRedirectsPatch;" + "->" + "parseRedirectUri(Ljava/lang/String;)Landroid/net/Uri;" ) 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 b8508db019..2fa9f8236f 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 @@ -5,10 +5,10 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.all.misc.transformation.BaseTransformInstructionsPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch -import app.revanced.patches.all.misc.transformation.AbstractTransformInstructionsPatch import com.android.tools.smali.dexlib2.iface.ClassDef import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction @@ -18,7 +18,8 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference @Patch( name = "Open links externally", - description = "Open links outside of the app directly in your browser.", + description = "Adds an option to always open links in your browser instead of in the in-app-browser.", + dependencies = [SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", @@ -28,14 +29,18 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] ) @Suppress("unused") -object OpenLinksExternallyPatch : AbstractTransformInstructionsPatch>( +object OpenLinksExternallyPatch : BaseTransformInstructionsPatch>( ) { override fun filterMap( classDef: ClassDef, method: Method, instruction: Instruction, instructionIndex: Int @@ -55,21 +60,16 @@ object OpenLinksExternallyPatch : AbstractTransformInstructionsPatchgetIntent(Ljava/lang/String;)Ljava/lang/String; + invoke-static {v$register}, Lapp/revanced/integrations/youtube/patches/OpenLinksExternallyPatch;->getIntent(Ljava/lang/String;)Ljava/lang/String; move-result-object v$register """ ) } override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_external_browser", - StringResource("revanced_external_browser_title", "Open links in browser"), - StringResource("revanced_external_browser_summary_on", "Opening links externally"), - StringResource("revanced_external_browser_summary_off", "Opening links in app") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_external_browser")) super.execute(context) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt index b19466aab8..e85f11c432 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/LithoFilterPatch.kt @@ -37,7 +37,7 @@ object LithoFilterPatch : BytecodePatch( private val Instruction.descriptor get() = (this as ReferenceInstruction).reference.toString() - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/LithoFilterPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/components/LithoFilterPatch;" internal lateinit var addFilter: (String) -> Unit private set 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 3704443d1f..561ac063a5 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.misc.minimizedplayback -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -8,8 +7,8 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.settings.preference.impl.NonInteractivePreference -import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.KidsMinimizedPlaybackPolicyControllerFingerprint import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint @@ -18,29 +17,29 @@ import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.Minimize 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.util.exception import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.MethodReference @Patch( name = "Minimized playback", - description = "Enables minimized and background playback.", + description = "Unlocks options for picture-in-picture and background playback.", dependencies = [ IntegrationsPatch::class, PlayerTypeHookPatch::class, VideoInformationPatch::class, - SettingsPatch::class + SettingsPatch::class, + AddResourcesPatch::class ], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -53,17 +52,19 @@ object MinimizedPlaybackPatch : BytecodePatch( KidsMinimizedPlaybackPolicyControllerFingerprint ) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/MinimizedPlaybackPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/youtube/patches/MinimizedPlaybackPatch;" override fun execute(context: BytecodeContext) { - // TODO: remove this empty preference sometime after mid 2023 + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.MISC.addPreferences( NonInteractivePreference( - StringResource("revanced_minimized_playback_enabled_title", "Minimized playback"), - StringResource( - "revanced_minimized_playback_summary_on", - "This setting can be found in Settings -> Background" - ) + "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 ) ) 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 23afdbb0cf..6dcc92c7dd 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 @@ -4,7 +4,7 @@ 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.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import java.io.Closeable @Patch(dependencies = [ResourceMappingPatch::class]) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/PlayerOverlaysHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/PlayerOverlaysHookPatch.kt index d4a7083b71..a48cc48c91 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/PlayerOverlaysHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/PlayerOverlaysHookPatch.kt @@ -26,7 +26,7 @@ object PlayerOverlaysHookPatch : BytecodePatch( // TODO: delete this unused outd val method = PlayerOverlaysOnFinishInflateFingerprint.result!!.mutableMethod method.addInstruction( method.implementation!!.instructions.size - 2, - "invoke-static { p0 }, Lapp/revanced/integrations/patches/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V" + "invoke-static { p0 }, Lapp/revanced/integrations/youtube/patches/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V" ) } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt index 186e3b1121..0e239e8d08 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/PlayerTypeHookPatch.kt @@ -20,7 +20,7 @@ object PlayerTypeHookPatch : BytecodePatch( setOf(PlayerTypeFingerprint, VideoStateFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/PlayerTypeHookPatch;" + "Lapp/revanced/integrations/youtube/patches/PlayerTypeHookPatch;" override fun execute(context: BytecodeContext) { PlayerTypeFingerprint.result?.mutableMethod?.addInstruction( 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 1a10eb1878..811836d4b8 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.misc.privacy -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 @@ -10,28 +9,33 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.privacy.fingerprints.CopyTextFingerprint import app.revanced.patches.youtube.misc.privacy.fingerprints.SystemShareSheetFingerprint import app.revanced.patches.youtube.misc.privacy.fingerprints.YouTubeShareSheetFingerprint import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Remove tracking query parameter", - description = "Remove the tracking query parameter from links you share.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to remove the tracking info from links you share.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -40,26 +44,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction object RemoveTrackingQueryParameterPatch : BytecodePatch( setOf(CopyTextFingerprint, SystemShareSheetFingerprint, YouTubeShareSheetFingerprint) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/RemoveTrackingQueryParameterPatch;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/RemoveTrackingQueryParameterPatch;" override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_remove_tracking_query_parameter", - StringResource( - "revanced_remove_tracking_query_parameter_title", - "Remove tracking query parameter" - ), - StringResource( - "revanced_remove_tracking_query_parameter_summary_on", - "Tracking query parameter is removed from links" - ), - StringResource( - "revanced_remove_tracking_query_parameter_summary_off", - "Tracking query parameter is not removed from links" - ), - ) - ) + AddResourcesPatch(this::class) + + 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 67ad2c00e5..d2360b8f1c 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 @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.misc.settings -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -8,11 +7,16 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen +import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch +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.IntentPreference +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.LicenseActivityFingerprint +import app.revanced.patches.youtube.misc.settings.fingerprints.LicenseActivityOnCreateFingerprint import app.revanced.patches.youtube.misc.settings.fingerprints.SetThemeFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.util.MethodUtil @@ -20,110 +24,95 @@ import java.io.Closeable @Patch( description = "Adds settings for ReVanced to YouTube.", - dependencies = [IntegrationsPatch::class, SettingsResourcePatch::class] + dependencies = [ + ChangePackageNamePatch::class, + IntegrationsPatch::class, + SettingsResourcePatch::class, + AddResourcesPatch::class + ] ) object SettingsPatch : BytecodePatch( - setOf(LicenseActivityFingerprint, SetThemeFingerprint) + setOf(LicenseActivityOnCreateFingerprint, SetThemeFingerprint) ), Closeable { - private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations" - private const val SETTINGS_ACTIVITY_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settingsmenu/ReVancedSettingActivity;" - private const val THEME_HELPER_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/utils/ThemeHelper;" - private const val SET_THEME_METHOD_NAME = "setTheme" + private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations/youtube" + private const val ACTIVITY_HOOK_CLASS_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settings/LicenseActivityHook;" + + private const val THEME_HELPER_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/ThemeHelper;" + private const val SET_THEME_METHOD_NAME: String = "setTheme" override fun execute(context: BytecodeContext) { - // TODO: Remove this when it is only required at one place. - fun getSetThemeInstructionString( - registers: String = "v0", - classDescriptor: String = THEME_HELPER_DESCRIPTOR, - methodName: String = SET_THEME_METHOD_NAME, - parameters: String = "Ljava/lang/Object;" - ) = "invoke-static { $registers }, $classDescriptor->$methodName($parameters)V" + AddResourcesPatch(this::class) + + PreferenceScreen.MISC.addPreferences( + TextPreference( + key = null, + 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" + ) + ) SetThemeFingerprint.result?.mutableMethod?.let { setThemeMethod -> setThemeMethod.implementation!!.instructions.mapIndexedNotNull { i, instruction -> - if (instruction.opcode == Opcode.RETURN_OBJECT) i else null - } - .asReversed() // Prevent index shifting. - .forEach { returnIndex -> - // The following strategy is to replace the return instruction with the setTheme instruction, - // then add a return instruction after the setTheme instruction. - // This is done because the return instruction is a target of another instruction. - - setThemeMethod.apply { - // This register is returned by the setTheme method. - val register = getInstruction(returnIndex).registerA - - val setThemeInstruction = getSetThemeInstructionString("v$register") - replaceInstruction(returnIndex, setThemeInstruction) - addInstruction(returnIndex + 1, "return-object v0") - } + if (instruction.opcode == Opcode.RETURN_OBJECT) i else null + }.asReversed().forEach { returnIndex -> + // The following strategy is to replace the return instruction with the setTheme instruction, + // then add a return instruction after the setTheme instruction. + // This is done because the return instruction is a target of another instruction. + + setThemeMethod.apply { + // This register is returned by the setTheme method. + val register = getInstruction(returnIndex).registerA + replaceInstruction( + returnIndex, + "invoke-static { v$register }, " + + "$THEME_HELPER_DESCRIPTOR->$SET_THEME_METHOD_NAME(Ljava/lang/Object;)V" + ) + addInstruction(returnIndex + 1, "return-object v$register") } + } } ?: throw SetThemeFingerprint.exception - // Modify the license activity and remove all existing layout code. // Must modify an existing activity and cannot add a new activity to the manifest, // as that fails for root installations. - LicenseActivityFingerprint.result!!.apply licenseActivity@{ - mutableMethod.apply { - fun buildSettingsActivityInvokeString( - registers: String = "p0", - classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR, - methodName: String = "initializeSettings", - parameters: String = "Landroid/app/Activity;" - ) = getSetThemeInstructionString(registers, classDescriptor, methodName, parameters) - - // initialize the settings - addInstructions( - 1, - """ - ${buildSettingsActivityInvokeString()} - return-void - """ - ) - } - - // remove method overrides - mutableClass.apply { + LicenseActivityOnCreateFingerprint.result?.let { result -> + result.mutableMethod.addInstructions( + 1, + """ + 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. + result.mutableClass.apply { methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) } } - } - - } - - fun addString(identifier: String, value: String, formatted: Boolean = true) = - SettingsResourcePatch.addString(identifier, value, formatted) - - fun addPreferenceScreen(preferenceScreen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) = - SettingsResourcePatch.addPreferenceScreen(preferenceScreen) - - fun addPreference(preference: Preference) = SettingsResourcePatch.addPreference(preference) - - fun renameIntentsTargetPackage(newPackage: String) { - SettingsResourcePatch.overrideIntentsTargetPackage = newPackage + } ?: throw LicenseActivityOnCreateFingerprint.exception } /** - * Creates an intent to open ReVanced settings of the given name + * Creates an intent to open ReVanced settings. */ - fun createReVancedSettingsIntent(settingsName: String) = Preference.Intent( - "com.google.android.youtube", - settingsName, - "com.google.android.libraries.social.licenses.LicenseActivity" - ) + fun newIntent(settingsName: String) = IntentPreference.Intent( + data = settingsName, + targetClass = "com.google.android.libraries.social.licenses.LicenseActivity" + ) { + // The package name change has to be reflected in the intent. + ChangePackageNamePatch.setOrGetFallbackPackageName("com.google.android.apps.youtube") + } - /** - * Preference screens patches should add their settings to. - */ - object PreferenceScreen : AbstractPreferenceScreen() { - val ADS = Screen("ads", "Ads", "Ad related settings") - val INTERACTIONS = Screen("interactions", "Interaction", "Settings related to interactions") - val LAYOUT = Screen("layout", "Layout", "Settings related to the layout") - val VIDEO = Screen("video", "Video", "Settings related to the video player") - val MISC = Screen("misc", "Misc", "Miscellaneous patches") + 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") - override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) { - addPreferenceScreen(screen) + 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 a95eb31a1c..b4b50461aa 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,63 +1,48 @@ package app.revanced.patches.youtube.misc.settings import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patcher.util.DomFileEditor -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.AbstractSettingsResourcePatch -import app.revanced.patches.shared.settings.preference.addPreference -import app.revanced.patches.shared.settings.preference.impl.* +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.BaseSettingsResourcePatch +import app.revanced.patches.shared.misc.settings.preference.IntentPreference import app.revanced.util.ResourceGroup import app.revanced.util.copyResources -import app.revanced.util.mergeStrings import org.w3c.dom.Element -import org.w3c.dom.Node -@Patch( - dependencies = [ResourceMappingPatch::class] -) -object SettingsResourcePatch : AbstractSettingsResourcePatch( - "revanced_prefs", - "settings" +object SettingsResourcePatch : BaseSettingsResourcePatch( + IntentPreference( + "revanced_settings", + intent = SettingsPatch.newIntent("revanced_settings_intent") + ) to "settings_fragment", + dependencies = setOf( + ResourceMappingPatch::class, + AddResourcesPatch::class, + ) ) { // Used for a fingerprint from SettingsPatch. internal var appearanceStringId = -1L - // if this is not null, all intents will be renamed to this - internal var overrideIntentsTargetPackage: String? = null - - private var preferencesNode: Node? = null - - private var preferencesEditor: DomFileEditor? = null - set(value) { - field = value - preferencesNode = value.getNode("PreferenceScreen") - } - override fun execute(context: ResourceContext) { super.execute(context) + AddResourcesPatch(this::class) + // Used for a fingerprint from SettingsPatch. appearanceStringId = ResourceMappingPatch.resourceMappings.find { it.type == "string" && it.name == "app_theme_appearance_dark" }!!.id - /* - * copy layout resources - */ arrayOf( ResourceGroup("layout", "revanced_settings_with_toolbar.xml") ).forEach { resourceGroup -> context.copyResources("settings", resourceGroup) } - preferencesEditor = context.xmlEditor["res/xml/settings_fragment.xml"] - - // Modify the manifest and add an data intent filter to the LicenseActivity. + // 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 -> - // An xml regular expression would probably work better than this manual searching. + // A xml regular-expression would probably work better than this manual searching. val manifestNodes = editor.file.getElementsByTagName("manifest").item(0).childNodes for (i in 0..manifestNodes.length) { val node = manifestNodes.item(i) @@ -79,90 +64,5 @@ object SettingsResourcePatch : AbstractSettingsResourcePatch( } } } - - - // Add the ReVanced settings to the YouTube settings - SettingsPatch.addPreference( - Preference( - StringResource("revanced_settings", "ReVanced"), - StringResource("revanced_settings_summary", "ReVanced specific settings"), - SettingsPatch.createReVancedSettingsIntent("revanced_settings") - ) - ) - - SettingsPatch.PreferenceScreen.MISC.addPreferences( - TextPreference( - key = null, - title = StringResource("revanced_pref_import_export_title", "Import / Export"), - summary = StringResource("revanced_pref_import_export_summary", "Import / Export ReVanced settings"), - inputType = InputType.TEXT_MULTI_LINE, - tag = "app.revanced.integrations.settingsmenu.ImportExportPreference" - ) - ) - - context.mergeStrings("settings/host/values/strings.xml") - } - - override fun close() { - super.close() - - // rename the intent package names if it was set - overrideIntentsTargetPackage?.let { packageName -> - val preferences = preferencesEditor!!.getNode("PreferenceScreen").childNodes - for (i in 1 until preferences.length) { - val preferenceNode = preferences.item(i) - // preferences have a child node with the intent tag, skip over every other node - if (preferenceNode.childNodes.length == 0) continue - - val intentNode = preferenceNode.firstChild - - // if the node doesn't have a target package attribute, skip it - val targetPackageAttribute = intentNode.attributes.getNamedItem("android:targetPackage") ?: continue - - // do not replace intent target package if the package name is not from YouTube - val youtubePackage = "com.google.android.youtube" - if (targetPackageAttribute.nodeValue != youtubePackage) continue - - // replace the target package name - intentNode.attributes.setNamedItem(preferenceNode.ownerDocument.createAttribute("android:targetPackage") - .also { attribute -> - attribute.value = packageName - }) - } - } - - preferencesEditor?.close() } - - /** - * Add a preference fragment to the main preferences. - * - * @param preference The preference to add. - */ - internal fun addPreference(preference: Preference) = - preferencesNode!!.addPreference(preference) { it.include() } - - /** - * Add a new string to the resources. - * - * @param identifier The key of the string. - * @param value The value of the string. - * @throws IllegalArgumentException if the string already exists. - */ - internal fun addString(identifier: String, value: String, formatted: Boolean) = - AbstractSettingsResourcePatch.addString(identifier, value, formatted) - - /** - * Add an array to the resources. - * - * @param arrayResource The array resource to add. - */ - internal fun addArray(arrayResource: ArrayResource) = AbstractSettingsResourcePatch.addArray(arrayResource) - - /** - * Add a preference to the settings. - * - * @param preferenceScreen The name of the preference screen. - */ - internal fun addPreferenceScreen(preferenceScreen: PreferenceScreen) = addPreference(preferenceScreen) } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/LicenseActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/LicenseActivityOnCreateFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/LicenseActivityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/LicenseActivityOnCreateFingerprint.kt index 87534b5830..ce3a4a7bbc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/LicenseActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/LicenseActivityOnCreateFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal object LicenseActivityFingerprint : MethodFingerprint( +internal object LicenseActivityOnCreateFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, returnType = "V", parameters = listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/SetThemeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/SetThemeFingerprint.kt index 28d9d41199..caf19d4269 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/SetThemeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/fingerprints/SetThemeFingerprint.kt @@ -12,4 +12,4 @@ internal object SetThemeFingerprint : LiteralValueFingerprint( parameters = listOf(), opcodes = listOf(Opcode.RETURN_OBJECT), literalSupplier = { SettingsResourcePatch.appearanceStringId } -) \ No newline at end of file +) 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 3c14f81a86..aadee4ab84 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 @@ -7,15 +7,15 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.zoomhaptics.fingerprints.ZoomHapticsFingerprint @Patch( name = "Disable zoom haptics", - description = "Disables haptics when zooming.", - dependencies = [SettingsPatch::class], + description = "Adds an option to disable haptics when zooming.", + dependencies = [SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [CompatiblePackage("com.google.android.youtube")] ) @Suppress("unused") @@ -23,21 +23,16 @@ object ZoomHapticsPatch : BytecodePatch( setOf(ZoomHapticsFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_disable_zoom_haptics", - StringResource("revanced_disable_zoom_haptics_title", "Disable zoom haptics"), - StringResource("revanced_disable_zoom_haptics_summary_on", "Haptics are disabled"), - StringResource("revanced_disable_zoom_haptics_summary_off", "Haptics are enabled") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.MISC.addPreferences(SwitchPreference("revanced_disable_zoom_haptics")) val zoomHapticsFingerprintMethod = ZoomHapticsFingerprint.result!!.mutableMethod zoomHapticsFingerprintMethod.addInstructionsWithLabels( 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/ZoomHapticsPatch;->shouldVibrate()Z + invoke-static { }, Lapp/revanced/integrations/youtube/patches/ZoomHapticsPatch;->shouldVibrate()Z move-result v0 if-nez v0, :vibrate return-void diff --git a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt new file mode 100644 index 0000000000..f54b9ee7c8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/HomeActivityFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.youtube.shared.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint + +internal object HomeActivityFingerprint : MethodFingerprint( + customFingerprint = { methodDef, classDef -> + methodDef.name == "onCreate" && classDef.type.endsWith("Shell_HomeActivity;") + }, +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/WatchWhileActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/MainActivityFingerprint.kt similarity index 55% rename from src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/WatchWhileActivityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/MainActivityFingerprint.kt index b7567b5692..f7573bd5de 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/WatchWhileActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/shared/fingerprints/MainActivityFingerprint.kt @@ -4,10 +4,12 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags -internal object WatchWhileActivityFingerprint : MethodFingerprint( +internal object MainActivityFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, parameters = listOf(), customFingerprint = { methodDef, _ -> - methodDef.definingClass.endsWith("WatchWhileActivity;") + methodDef.definingClass.endsWith("MainActivity;") + // Old versions of YouTube called this class "WatchWhileActivity" instead. + || methodDef.definingClass.endsWith("WatchWhileActivity;") } ) 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 d565d0a40c..f777c10a2f 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 @@ -5,8 +5,8 @@ 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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +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 import app.revanced.patches.youtube.video.hdrbrightness.fingerprints.HDRBrightnessFingerprint @@ -16,8 +16,8 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Patch( name = "HDR auto brightness", - description = "Makes the brightness of HDR videos follow the system default.", - dependencies = [IntegrationsPatch::class, SettingsPatch::class], + description = "Adds an option to make the brightness of HDR videos follow the system default.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class, AddResourcesPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ @@ -26,8 +26,12 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -37,14 +41,9 @@ object HDRBrightnessPatch : BytecodePatch( setOf(HDRBrightnessFingerprint) ) { override fun execute(context: BytecodeContext) { - SettingsPatch.PreferenceScreen.VIDEO.addPreferences( - SwitchPreference( - "revanced_hdr_auto_brightness", - StringResource("revanced_hdr_auto_brightness_title", "Enable auto HDR brightness"), - StringResource("revanced_hdr_auto_brightness_summary_on", "Auto HDR brightness is enabled"), - StringResource("revanced_hdr_auto_brightness_summary_off", "Auto HDR brightness is disabled") - ) - ) + AddResourcesPatch(this::class) + + SettingsPatch.PreferenceScreen.VIDEO.addPreferences(SwitchPreference("revanced_hdr_auto_brightness")) val method = HDRBrightnessFingerprint.result!!.mutableMethod @@ -59,7 +58,7 @@ object HDRBrightnessPatch : BytecodePatch( method.addInstructions( insertIndex, """ - invoke-static {v$register}, Lapp/revanced/integrations/patches/HDRAutoBrightnessPatch;->getHDRBrightness(F)F + invoke-static {v$register}, Lapp/revanced/integrations/youtube/patches/HDRAutoBrightnessPatch;->getHDRBrightness(F)F move-result v$register """ ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt index 1de0f90a3e..36d0066c6f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/VideoInformationPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.video.information -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -14,13 +13,14 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.video.information.fingerprints.* import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch +import app.revanced.util.exception import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.BuilderInstruction import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation -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 +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.util.MethodUtil @@ -37,7 +37,7 @@ object VideoInformationPatch : BytecodePatch( OnPlaybackSpeedItemClickFingerprint ) ) { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/VideoInformation;" + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/VideoInformation;" private lateinit var playerInitMethod: MutableMethod private var playerInitInsertIndex = 4 @@ -135,23 +135,24 @@ object VideoInformationPatch : BytecodePatch( */ videoTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime") - /* * Hook the user playback speed selection */ - OnPlaybackSpeedItemClickFingerprint.result?.apply { - speedSelectionInsertMethod = mutableMethod - speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3 + OnPlaybackSpeedItemClickFingerprint.result?.mutableMethod?.apply { + speedSelectionInsertMethod = this + val speedSelectionMethodInstructions = this.implementation!!.instructions + val speedSelectionValueInstructionIndex = speedSelectionMethodInstructions.indexOfFirst { + it.opcode == Opcode.IGET + } speedSelectionValueRegister = - mutableMethod.getInstruction(speedSelectionInsertIndex).registerD - - val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions - setPlaybackSpeedContainerClassFieldReference = - getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ) + getInstruction(speedSelectionValueInstructionIndex).registerA setPlaybackSpeedClassFieldReference = - getReference(speedSelectionMethodInstructions, 1, Opcode.IGET) + getInstruction(speedSelectionValueInstructionIndex + 1).reference.toString() setPlaybackSpeedMethodReference = - getReference(speedSelectionMethodInstructions, 2, Opcode.IGET) + getInstruction(speedSelectionValueInstructionIndex + 2).reference.toString() + setPlaybackSpeedContainerClassFieldReference = + getReference(speedSelectionMethodInstructions, -1, Opcode.IF_EQZ) + speedSelectionInsertIndex = speedSelectionValueInstructionIndex + 1 } ?: throw OnPlaybackSpeedItemClickFingerprint.exception userSelectedPlaybackSpeedHook(INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed") diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt index 8a3a700afc..249d659b91 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt @@ -2,18 +2,19 @@ package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.util.getReference import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.reference.FieldReference internal object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, returnType = "V", parameters = listOf("L", "L", "I", "J"), - customFingerprint = { methodDef, _ -> methodDef.name == "onItemClick" }, - opcodes = listOf( - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID - ) + customFingerprint = { methodDef, _ -> + methodDef.name == "onItemClick" && methodDef.implementation?.instructions?.find { + it.opcode == Opcode.IGET_OBJECT && + it.getReference()!!.type == "Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;" + } != null + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt index 3811b761fd..135779eec2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/playerresponse/PlayerResponseMethodHookPatch.kt @@ -18,29 +18,44 @@ object PlayerResponseMethodHookPatch : BytecodePatch(setOf(PlayerParameterBuilderFingerprint)), Closeable, MutableSet by mutableSetOf() { - private const val VIDEO_ID_PARAMETER = 1 - private const val IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER = 11 - private const val PROTO_BUFFER_PARAMETER_PARAMETER = 3 + + // Parameter numbers of the patched method. + private const val PARAMETER_VIDEO_ID = 1 + private const val PARAMETER_PROTO_BUFFER = 3 + private const val PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING = 11 + + // Temporary 4-bit registers used to pass the parameters to integrations. + private const val REGISTER_VIDEO_ID = 0 + private const val REGISTER_PROTO_BUFFER = 1 + private const val REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING = 2 private lateinit var playerResponseMethod: MutableMethod + private var numberOfInstructionsAdded = 0 + override fun execute(context: BytecodeContext) { playerResponseMethod = PlayerParameterBuilderFingerprint.result?.mutableMethod ?: throw PlayerParameterBuilderFingerprint.exception } override fun close() { - fun hookVideoId(hook: Hook) = playerResponseMethod.addInstruction( - 0, "invoke-static {p$VIDEO_ID_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook" - ) + fun hookVideoId(hook: Hook) { + playerResponseMethod.addInstruction( + 0, "invoke-static {v$REGISTER_VIDEO_ID, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook" + ) + numberOfInstructionsAdded++ + } - fun hookProtoBufferParameter(hook: Hook) = playerResponseMethod.addInstructions( - 0, - """ - invoke-static {p$PROTO_BUFFER_PARAMETER_PARAMETER, p$IS_SHORT_AND_OPENING_OR_PLAYING_PARAMETER}, $hook - move-result-object p$PROTO_BUFFER_PARAMETER_PARAMETER + fun hookProtoBufferParameter(hook: Hook) { + playerResponseMethod.addInstructions( + 0, + """ + invoke-static {v$REGISTER_PROTO_BUFFER, v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING}, $hook + move-result-object v$REGISTER_PROTO_BUFFER """ - ) + ) + numberOfInstructionsAdded += 2 + } // Reverse the order in order to preserve insertion order of the hooks. val beforeVideoIdHooks = filterIsInstance().asReversed() @@ -51,6 +66,23 @@ object PlayerResponseMethodHookPatch : afterVideoIdHooks.forEach(::hookProtoBufferParameter) videoIdHooks.forEach(::hookVideoId) beforeVideoIdHooks.forEach(::hookProtoBufferParameter) + + // On some app targets the method has too many registers pushing the parameters past v15. + // Move the parameters to 4-bit registers so they can be passed to integrations. + playerResponseMethod.addInstructions( + 0, """ + move-object/from16 v$REGISTER_VIDEO_ID, p$PARAMETER_VIDEO_ID + move-object/from16 v$REGISTER_PROTO_BUFFER, p$PARAMETER_PROTO_BUFFER + move/from16 v$REGISTER_IS_SHORT_AND_OPENING_OR_PLAYING, p$PARAMETER_IS_SHORT_AND_OPENING_OR_PLAYING + """, + ) + numberOfInstructionsAdded += 3 + + // Move the modified register back. + playerResponseMethod.addInstruction( + numberOfInstructionsAdded, + "move-object/from16 p$PARAMETER_PROTO_BUFFER, v$REGISTER_PROTO_BUFFER" + ) } internal abstract class Hook(private val methodDescriptor: String) { diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt index 1f1ca33759..8be8537e4b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/RememberVideoQualityPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.video.quality -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -9,10 +8,9 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference +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 import app.revanced.patches.youtube.video.information.VideoInformationPatch @@ -20,24 +18,28 @@ import app.revanced.patches.youtube.video.quality.fingerprints.NewVideoQualityCh import app.revanced.patches.youtube.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySetterFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Patch( name = "Remember video quality", - description = "Adds the ability to remember the last video quality selected.", - dependencies = [IntegrationsPatch::class, VideoInformationPatch::class, SettingsPatch::class], + description = "Adds an option to remember the last video quality selected.", + dependencies = [ + IntegrationsPatch::class, + VideoInformationPatch::class, + SettingsPatch::class, + AddResourcesPatch::class + ], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -51,68 +53,24 @@ object RememberVideoQualityPatch : BytecodePatch( ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;" + "Lapp/revanced/integrations/youtube/patches/playback/quality/RememberVideoQualityPatch;" override fun execute(context: BytecodeContext) { - // This is bloated as each value has it's own String key/value - // ideally the entries would be raw values (and not a key to a String resource) - val entries = listOf( - StringResource("revanced_video_quality_default_entry_1", "Automatic quality"), - StringResource("revanced_video_quality_default_entry_2", "2160p"), - StringResource("revanced_video_quality_default_entry_3", "1440p"), - StringResource("revanced_video_quality_default_entry_4", "1080p"), - StringResource("revanced_video_quality_default_entry_5", "720p"), - StringResource("revanced_video_quality_default_entry_6", "480p"), - StringResource("revanced_video_quality_default_entry_7", "360p"), - StringResource("revanced_video_quality_default_entry_8", "240p"), - StringResource("revanced_video_quality_default_entry_9", "144p"), - ) - val entryValues = listOf( - StringResource("revanced_video_quality_default_entry_value_1", "-2"), - StringResource("revanced_video_quality_default_entry_value_2", "2160"), - StringResource("revanced_video_quality_default_entry_value_3", "1440"), - StringResource("revanced_video_quality_default_entry_value_4", "1080"), - StringResource("revanced_video_quality_default_entry_value_5", "720"), - StringResource("revanced_video_quality_default_entry_value_6", "480"), - StringResource("revanced_video_quality_default_entry_value_7", "360"), - StringResource("revanced_video_quality_default_entry_value_8", "240"), - StringResource("revanced_video_quality_default_entry_value_9", "144"), - ) + AddResourcesPatch(this::class) SettingsPatch.PreferenceScreen.VIDEO.addPreferences( - SwitchPreference( - "revanced_remember_video_quality_last_selected", - StringResource( - "revanced_remember_video_quality_last_selected_title", - "Remember video quality changes" - ), - StringResource( - "revanced_remember_video_quality_last_selected_summary_on", - "Quality changes apply to all videos" - ), - StringResource( - "revanced_remember_video_quality_last_selected_summary_off", - "Quality changes only apply to the current video" - ) - ), + SwitchPreference("revanced_remember_video_quality_last_selected"), ListPreference( - "revanced_video_quality_default_wifi", - StringResource( - "revanced_video_quality_default_wifi_title", - "Default video quality on Wi-Fi network" - ), - ArrayResource("revanced_video_quality_default_wifi_entry", entries), - ArrayResource("revanced_video_quality_default_wifi_entry_values", entryValues) - // default value and summary are set by integrations after loading + key = "revanced_video_quality_default_wifi", + summaryKey = null, + entriesKey = "revanced_video_quality_default_entries", + entryValuesKey = "revanced_video_quality_default_entry_values" ), ListPreference( - "revanced_video_quality_default_mobile", - StringResource( - "revanced_video_quality_default_mobile_title", - "Default video quality on mobile network" - ), - ArrayResource("revanced_video_quality_default_mobile_entries", entries), - ArrayResource("revanced_video_quality_default_mobile_values", entryValues) + key = "revanced_video_quality_default_mobile", + summaryKey = null, + entriesKey = "revanced_video_quality_default_entries", + entryValuesKey = "revanced_video_quality_default_entry_values" ) ) 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 8cd2146aa5..d58a99f4ef 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 @@ -9,18 +9,16 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa @Patch( name = "Playback speed", - description = "Adds custom playback speeds and ability to remember the last playback speed selected.", + description = "Adds options to customize available playback speeds and to remember the last playback speed selected.", dependencies = [CustomPlaybackSpeedPatch::class, RememberPlaybackSpeedPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ - "18.32.39", - "18.37.36", - "18.38.44", - "18.43.45", - "18.44.41", - "18.45.41", - "18.45.43" + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt index 4c572ffa6c..061207c085 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.video.speed.custom -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -11,14 +10,15 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.TextPreference -import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch +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.TextPreference import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.LithoFilterPatch +import app.revanced.patches.youtube.misc.recyclerviewtree.hook.RecyclerViewTreeHookPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.video.speed.custom.fingerprints.* +import app.revanced.util.exception import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -29,7 +29,14 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableField @Patch( description = "Adds custom playback speed options.", - dependencies = [IntegrationsPatch::class, LithoFilterPatch::class, SettingsPatch::class, RecyclerViewTreeHookPatch::class] + dependencies = [ + IntegrationsPatch::class, + LithoFilterPatch::class, + SettingsPatch::class, + RecyclerViewTreeHookPatch::class, + CustomPlaybackSpeedResourcePatch::class, + AddResourcesPatch::class + ] ) object CustomPlaybackSpeedPatch : BytecodePatch( setOf( @@ -40,25 +47,16 @@ object CustomPlaybackSpeedPatch : BytecodePatch( ) ) { private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch;" + "Lapp/revanced/integrations/youtube/patches/components/PlaybackSpeedMenuFilterPatch;" private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/playback/speed/CustomPlaybackSpeedPatch;" + "Lapp/revanced/integrations/youtube/patches/playback/speed/CustomPlaybackSpeedPatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( - TextPreference( - key = "revanced_custom_playback_speeds", - title = StringResource( - "revanced_custom_playback_speeds_title", - "Custom playback speeds" - ), - inputType = InputType.TEXT_MULTI_LINE, - summary = StringResource( - "revanced_custom_playback_speeds_summary", - "Add or change the available playback speeds" - ) - ) + TextPreference("revanced_custom_playback_speeds", inputType = InputType.TEXT_MULTI_LINE) ) val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!! diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedResourcePatch.kt new file mode 100644 index 0000000000..2fc51faaa8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/CustomPlaybackSpeedResourcePatch.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.video.speed.custom + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch + +internal object CustomPlaybackSpeedResourcePatch : ResourcePatch() { + var speedUnavailableId: Long = -1 + + override fun execute(context: ResourceContext) { + speedUnavailableId = ResourceMappingPatch.resourceMappings.single { + it.type == "string" && it.name == "varispeed_unavailable_message" + }.id + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldPlaybackSpeedMenuFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldPlaybackSpeedMenuFingerprint.kt index 4df113decc..f893eb9043 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldPlaybackSpeedMenuFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/ShowOldPlaybackSpeedMenuFingerprint.kt @@ -1,7 +1,10 @@ package app.revanced.patches.youtube.video.speed.custom.fingerprints -import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patches.youtube.video.speed.custom.CustomPlaybackSpeedResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint -internal object ShowOldPlaybackSpeedMenuFingerprint : MethodFingerprint( - strings = listOf("PLAYBACK_RATE_MENU_BOTTOM_SHEET_FRAGMENT") +internal object ShowOldPlaybackSpeedMenuFingerprint : LiteralValueFingerprint( + literalSupplier = { + CustomPlaybackSpeedResourcePatch.speedUnavailableId + } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/RememberPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/RememberPlaybackSpeedPatch.kt index c37c7792c6..cc30d0de4c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/RememberPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/RememberPlaybackSpeedPatch.kt @@ -1,72 +1,55 @@ package app.revanced.patches.youtube.video.speed.remember -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.settings.preference.ListPreference +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 import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.patches.youtube.video.speed.custom.CustomPlaybackSpeedPatch import app.revanced.patches.youtube.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @Patch( - dependencies = [IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomPlaybackSpeedPatch::class] + dependencies = [ + IntegrationsPatch::class, + SettingsPatch::class, + VideoInformationPatch::class, + CustomPlaybackSpeedPatch::class, + AddResourcesPatch::class + ] ) object RememberPlaybackSpeedPatch : BytecodePatch( setOf(InitializePlaybackSpeedValuesFingerprint) -){ +) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;" + "Lapp/revanced/integrations/youtube/patches/playback/speed/RememberPlaybackSpeedPatch;" override fun execute(context: BytecodeContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( - SwitchPreference( - "revanced_remember_playback_speed_last_selected", - StringResource( - "revanced_remember_playback_speed_last_selected_title", - "Remember playback speed changes" - ), - StringResource( - "revanced_remember_playback_speed_last_selected_summary_on", - "Playback speed changes apply to all videos" - ), - StringResource( - "revanced_remember_playback_speed_last_selected_summary_off", - "Playback speed changes only apply to the current video" - ) - ), + SwitchPreference("revanced_remember_playback_speed_last_selected"), ListPreference( - "revanced_playback_speed_default", - StringResource( - "revanced_playback_speed_default_title", - "Default playback speed" - ), - // Dummy data: - // Entries and values are set by Integrations code based on the actual speeds available, - // and the values set here are ignored and do nothing. - ArrayResource( - "revanced_playback_speed_default_entries", - listOf(StringResource("revanced_playback_speed_default_entries", "1.0x")) - ), - ArrayResource( - "revanced_playback_speed_default_entry_values", - listOf(StringResource("revanced_playback_speed_default_entry_value", "1.0")) - ) + key = "revanced_playback_speed_default", + summaryKey = null, + // Entries and values are set by Integrations code based on the actual speeds available. + entriesKey = null, + entryValuesKey = null ) ) VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted") VideoInformationPatch.userSelectedPlaybackSpeedHook( - INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed") + INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed" + ) /* * Hook the code that is called when the playback speeds are initialized, and sets the playback speed diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt index 63295cb8f5..efe99d7afd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/VideoIdPatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.video.videoid -import app.revanced.util.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction @@ -13,6 +12,7 @@ import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprint import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay +import app.revanced.util.exception import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( @@ -49,7 +49,7 @@ object VideoIdPatch : BytecodePatch( consumer(it, insertIndex, videoIdRegister) } - } ?: throw VideoIdFingerprint.exception + } ?: throw exception VideoIdFingerprint.setFields { method, index, register -> videoIdMethod = method diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt index dfc90619c5..a01b2ebdcc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt @@ -10,19 +10,13 @@ internal object VideoIdFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L"), opcodes = listOf( - Opcode.MOVE_RESULT_OBJECT, - Opcode.IF_EQZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT, Opcode.IF_EQZ, Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT + Opcode.MOVE_RESULT_OBJECT, ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt index 8a265c915f..5bc5d4fd3b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt @@ -10,18 +10,10 @@ internal object VideoIdFingerprintBackgroundPlay : MethodFingerprint( accessFlags = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, parameters = listOf("L"), opcodes = listOf( - Opcode.MONITOR_EXIT, - Opcode.RETURN_VOID, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.NEW_ARRAY, - Opcode.SGET_OBJECT, - Opcode.APUT_OBJECT, Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT, Opcode.IF_EQZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_OBJECT, Opcode.IF_EQZ, Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT, diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt index e72ce38ef2..6ccfdf9cd8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt @@ -14,7 +14,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( name = "Restore old video quality menu", - description = "Restores the old video quality with advanced video quality options.", + description = "Adds an option to restore the old video quality menu with specific video resolution options.", dependencies = [ IntegrationsPatch::class, RestoreOldVideoQualityMenuResourcePatch::class, @@ -30,8 +30,12 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.38.44", "18.43.45", "18.44.41", - "18.45.41", - "18.45.43" + "18.45.43", + "18.48.39", + "18.49.37", + "19.01.34", + "19.02.39", + "19.03.35" ] ) ] @@ -41,10 +45,10 @@ object RestoreOldVideoQualityMenuPatch : BytecodePatch( setOf(VideoQualityMenuViewInflateFingerprint) ) { private const val FILTER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/components/VideoQualityMenuFilterPatch;" + "Lapp/revanced/integrations/youtube/patches/components/VideoQualityMenuFilterPatch;" private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/playback/quality/RestoreOldVideoQualityMenuPatch;" + "Lapp/revanced/integrations/youtube/patches/playback/quality/RestoreOldVideoQualityMenuPatch;" override fun execute(context: BytecodeContext) { // region Patch for the old type of the video quality menu. diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt index b16e1066fd..7221e80b1d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt @@ -4,25 +4,22 @@ 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.patches.shared.mapping.misc.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( - dependencies = [SettingsPatch::class, ResourceMappingPatch::class] + dependencies = [SettingsPatch::class, ResourceMappingPatch::class, AddResourcesPatch::class] ) object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() { internal var videoQualityBottomSheetListFragmentTitle = -1L override fun execute(context: ResourceContext) { + AddResourcesPatch(this::class) + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( - SwitchPreference( - "revanced_restore_old_video_quality_menu", - StringResource("revanced_restore_old_video_quality_menu_title", "Restore old video quality menu"), - StringResource("revanced_restore_old_video_quality_menu_summary_on", "Old video quality menu is shown"), - StringResource("revanced_restore_old_video_quality_menu_summary_off", "Old video quality menu is not shown") - ) + SwitchPreference("revanced_restore_old_video_quality_menu") ) fun findResource(name: String) = ResourceMappingPatch.resourceMappings.find { it.name == name }?.id diff --git a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt index ea7e88d14c..f47ae90df3 100644 --- a/src/main/kotlin/app/revanced/util/BytecodeUtils.kt +++ b/src/main/kotlin/app/revanced/util/BytecodeUtils.kt @@ -7,7 +7,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.patch.PatchException import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch +import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction diff --git a/src/main/kotlin/app/revanced/util/ResourceUtils.kt b/src/main/kotlin/app/revanced/util/ResourceUtils.kt index d7aef39b6e..c5b502cb16 100644 --- a/src/main/kotlin/app/revanced/util/ResourceUtils.kt +++ b/src/main/kotlin/app/revanced/util/ResourceUtils.kt @@ -2,14 +2,33 @@ package app.revanced.util import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.util.DomFileEditor -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.youtube.misc.settings.SettingsPatch +import app.revanced.patches.all.misc.resources.AddResourcesPatch +import app.revanced.util.resource.BaseResource import org.w3c.dom.Node +import org.w3c.dom.NodeList +import java.io.InputStream import java.nio.file.Files import java.nio.file.StandardCopyOption private val classLoader = object {}.javaClass.classLoader +/** + * Returns a sequence for all child nodes. + */ +fun NodeList.asSequence() = (0 until this.length).asSequence().map { this.item(it) } + +/** + * Returns a sequence for all child nodes. + */ +fun Node.childElementsSequence() = this.childNodes.asSequence().filter { it.nodeType == Node.ELEMENT_NODE } + +/** + * Performs the given [action] on each child element. + */ +fun Node.forEachChildElement(action: (Node) -> Unit) = childElementsSequence().forEach { + action(it) +} + /** * Recursively traverse the DOM tree starting from the given root node. * @@ -20,26 +39,6 @@ fun Node.doRecursively(action: (Node) -> Unit) { for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action) } -/** - * Merge strings. This manages [StringResource]s automatically. - * - * @param host The hosting xml resource. Needs to be a valid strings.xml resource. - */ -fun ResourceContext.mergeStrings(host: String) { - this.iterateXmlNodeChildren(host, "resources") { - // TODO: figure out why this is needed - if (!it.hasAttributes()) return@iterateXmlNodeChildren - - val attributes = it.attributes - val key = attributes.getNamedItem("name")!!.nodeValue!! - val value = it.textContent!! - - val formatted = attributes.getNamedItem("formatted") == null - - SettingsPatch.addString(key, value, formatted) - } -} - /** * Copy resources from the current class loader to the resource directory. * @@ -53,13 +52,18 @@ fun ResourceContext.copyResources(sourceResourceDirectory: String, vararg resour resourceGroup.resources.forEach { resource -> val resourceFile = "${resourceGroup.resourceDirectoryName}/$resource" Files.copy( - classLoader.getResourceAsStream("$sourceResourceDirectory/$resourceFile")!!, + inputStreamFromBundledResource(sourceResourceDirectory, resourceFile)!!, targetResourceDirectory.resolve(resourceFile).toPath(), StandardCopyOption.REPLACE_EXISTING ) } } } +internal fun inputStreamFromBundledResource( + sourceResourceDirectory: String, + resourceFile: String +): InputStream? = classLoader.getResourceAsStream("$sourceResourceDirectory/$resourceFile") + /** * Resource names mapped to their corresponding resource data. * @param resourceDirectoryName The name of the directory of the resource. @@ -106,4 +110,16 @@ fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoClosea source.close() target.close() } -} \ No newline at end of file +} + +/** + * 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 = { }) { + appendChild(resource.serialize(ownerDocument, resourceCallback)) +} + +internal fun DomFileEditor?.getNode(tagName: String) = this!!.file.getElementsByTagName(tagName).item(0) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/resource/ArrayResource.kt b/src/main/kotlin/app/revanced/util/resource/ArrayResource.kt new file mode 100644 index 0000000000..190085bd54 --- /dev/null +++ b/src/main/kotlin/app/revanced/util/resource/ArrayResource.kt @@ -0,0 +1,37 @@ +package app.revanced.util.resource + +import app.revanced.util.childElementsSequence +import org.w3c.dom.Document +import org.w3c.dom.Node + +/** + * An array resource. + * + * @param name The name of the array resource. + * @param items The items of the array resource. + */ +@Suppress("MemberVisibilityCanBePrivate") +class ArrayResource( + name: String, + val items: List, +) : BaseResource(name, "string-array") { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + setAttribute("name", name) + + items.forEach { item -> + appendChild(ownerDocument.createElement("item").also { itemNode -> + itemNode.textContent = item + }) + } + } + + companion object { + fun fromNode(node: Node): ArrayResource { + val key = node.attributes.getNamedItem("name").textContent + val items = node.childElementsSequence().map { it.textContent }.toList() + + return ArrayResource(key, items) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt b/src/main/kotlin/app/revanced/util/resource/BaseResource.kt similarity index 63% rename from src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt rename to src/main/kotlin/app/revanced/util/resource/BaseResource.kt index 682ccb33ae..7093bffaf3 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt +++ b/src/main/kotlin/app/revanced/util/resource/BaseResource.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.settings.preference +package app.revanced.util.resource import org.w3c.dom.Document import org.w3c.dom.Element @@ -9,6 +9,7 @@ import org.w3c.dom.Element * @param name The name of the resource. * @param tag The tag of the resource. */ +@Suppress("MemberVisibilityCanBePrivate") abstract class BaseResource( val name: String, val tag: String @@ -24,4 +25,19 @@ abstract class BaseResource( setAttribute("name", name) } } + + override fun hashCode(): Int { + var result = name.hashCode() + result = 31 * result + tag.hashCode() + return result + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as BaseResource + + return name == other.name + } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/resource/StringResource.kt b/src/main/kotlin/app/revanced/util/resource/StringResource.kt new file mode 100644 index 0000000000..c825d67598 --- /dev/null +++ b/src/main/kotlin/app/revanced/util/resource/StringResource.kt @@ -0,0 +1,41 @@ +package app.revanced.util.resource + +import app.revanced.patcher.patch.PatchException +import org.w3c.dom.Document +import org.w3c.dom.Node + +/** + * A string value. + * Represents a string in the strings.xml file. + * + * @param name The name of the string. + * @param value The value of the string. + * @param formatted If the string is formatted. Defaults to `true`. + */ +class StringResource( + name: String, + val value: String, + val formatted: Boolean = true, +) : BaseResource(name, "string") { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + // if the string is un-formatted, explicitly add the formatted attribute + if (!formatted) setAttribute("formatted", "false") + + if (value.contains(Regex("(? + + + + @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 + + + + + @string/revanced_start_page_home_entry_0 + @string/revanced_start_page_home_entry_1 + @string/revanced_start_page_search_entry_2 + @string/revanced_start_page_subscriptions_entry_3 + @string/revanced_start_page_explore_entry_4 + @string/revanced_start_page_shorts_entry_5 + + + + MAIN + open.search + open.subscriptions + open.explore + open.shorts + + + + + @string/revanced_alt_thumbnail_stills_time_entry_1 + @string/revanced_alt_thumbnail_stills_time_entry_2 + @string/revanced_alt_thumbnail_stills_time_entry_3 + + + 1 + 2 + 3 + + + + + @string/revanced_video_quality_default_entry_1 + @string/revanced_video_quality_default_entry_2 + @string/revanced_video_quality_default_entry_3 + @string/revanced_video_quality_default_entry_4 + @string/revanced_video_quality_default_entry_5 + @string/revanced_video_quality_default_entry_6 + @string/revanced_video_quality_default_entry_7 + @string/revanced_video_quality_default_entry_8 + @string/revanced_video_quality_default_entry_9 + + + -2 + 2160 + 1440 + 1080 + 720 + 480 + 360 + 240 + 144 + + + + + + + @string/revanced_deleted_messages_entry_1 + @string/revanced_deleted_messages_entry_2 + @string/revanced_deleted_messages_entry_3 + + + hide + spoiler + cross-out + + + + + @string/revanced_hls_proxies_entry_1 + @string/revanced_hls_proxies_entry_2 + @string/revanced_hls_proxies_entry_3 + + + disabled + luminous + purpleadblock + + + + \ No newline at end of file diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml new file mode 100644 index 0000000000..e312ffe5bc --- /dev/null +++ b/src/main/resources/addresources/values/strings.xml @@ -0,0 +1,1020 @@ + + + + ReVanced + Do you wish to proceed? + Reset + Refresh and restart + Restart + Import + Copy + ReVanced settings reset to default + Imported %d settings + Import failed: %s + + + GmsCore is not installed. Please install. + GmsCore is failing to run. Please follow the \"Don\'t kill my app\" guide for GmsCore. + + + + + 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 + + + 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 + Log stack traces + Debug logs include stack trace + Debug logs do not include stack trace + Show toast on ReVanced error + 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 + Watermark is hidden + Watermark is shown + Hide \'For you\' shelf in channel page + Shelf is hidden + Shelf is shown + Hide \'Notify me\' button + Button is hidden + Button is shown + Hide timed reactions + Timed reactions are hidden + Timed reactions are shown + Hide \'People also watched\' recommendations + Recommendations are hidden + Recommendations are shown + Hide search result shelf header + Shelf header is hidden + Shelf header is shown + Hide channel guidelines + Channel guidelines are hidden + Channel guidelines are shown + Hide expandable chip under videos + Expandable chips are hidden + Expandable chips are shown + 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 + Hide compact banners + Compact banners are hidden + Compact banners are shown + Hide movies section + Movies section is hidden + Movies section is shown + Hide feed surveys + Feed surveys are hidden + Feed surveys are shown + Hide community guidelines + Community guidelines are hidden + Community guidelines are shown + Hide subscribers community guidelines + Subscribers community guidelines are hidden + Subscribers community guidelines are shown + Hide channel member shelf + Channel member shelf is hidden + Channel member shelf is shown + Hide emergency boxes + Emergency boxes are hidden + Emergency boxes are shown + Hide info panels + Info panels are hidden + Info panels are shown + Hide medical panels + Medical panels are hidden + Medical panels are shown + Hide channel bar + Channel bar is hidden + Channel bar is shown + Hide quick actions in fullscreen + Quick actions are hidden + Quick actions are shown + Hide related videos in quick actions + Related videos are hidden + Related videos are shown + Hide image shelf in search results + Image shelf is hidden + Image shelf is shown + Hide latest posts + Latest posts are hidden + Latest posts are shown + Hide mix playlists + Mix playlists are hidden + Mix playlists are shown + Hide artist cards + Artist cards are hidden + Artist cards are shown + 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 game section + Game section is hidden + Game section is shown + Hide music section + Music section is hidden + Music section is shown + Hide podcast section + Podcast section is hidden + Podcast section is shown + Hide transcript section + Transcript section is hidden + Transcript section is shown + Hide components under the video description + Custom filter + 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 + + + Hide general ads + General ads are hidden + General ads are shown + Hide fullscreen ads + Fullscreen ads are hidden + Fullscreen ads are shown + Hide buttoned ad + Buttoned ads are hidden + Buttoned ads are shown + Hide paid content + Paid content is hidden + Paid content is shown + Hide self sponsored cards + Self sponsored cards are hidden + Self sponsored cards are shown + Hide banner to view products + Banner is hidden + Banner is shown + Hide shopping links in video description + Shopping links are hidden + Shopping links are shown + Hide web search results + Web search results are hidden + Web search results are shown + Hide merchandise banners + Merchandise banners are hidden + Merchandise banners are shown + + + Hide YouTube Premium promotions + YouTube Premium promotions under video player are hidden + YouTube Premium promotions under video player are shown + + + Hide video ads + Video ads are hidden + Video ads are shown + + + 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 + Dialog will be removed + Dialog will be shown + This does not bypass the age restriction. It just accepts it automatically. + + + %s is not installed. Please install it. + External download settings + 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 + + + Disable precise seeking gesture + Gesture is disabled + Gesture is enabled + + + Enable seekbar tapping + Seekbar tapping is enabled + Seekbar tapping is disabled + + + Swipe controls + Enable brightness gesture + Brightness swipe is enabled + Brightness swipe is disabled + Enable volume gesture + Volume swipe is enabled + Volume swipe is disabled + Enable press-to-swipe gesture + Press-to-swipe is enabled + Press-to-swipe is disabled + Enable haptic feedback + Haptic feedback is enabled + Haptic feedback is disabled + Save and restore brightness + Save and restore brightness when exiting or entering fullscreen + Do not save and restore brightness when exiting or entering fullscreen + Swipe overlay timeout + The amount of milliseconds the overlay is visible + Swipe overlay text size + The text size for swipe overlay + Swipe background visibility + The visibility of swipe overlay background + Swipe magnitude threshold + The amount of threshold for swipe to occur + Control volume and brightness + + + Disable auto captions + Auto captions are disabled + 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 + Share button is hidden + Share button is shown + Hide report button + Report button is hidden + Report button is shown + Hide remix button + Remix button is hidden + Remix button is shown + Hide download button + Download button is hidden + Download button is shown + Hide thanks button + Thanks button is hidden + Thanks button is shown + Hide clip button + Clip button is hidden + Clip button is shown + Hide save to playlist button + Save button is hidden + Save button is shown + Hide shop button + Shop button is hidden + Shop button is shown + Hide or show buttons under videos + + + Hide autoplay button + Autoplay button is hidden + Autoplay button is shown + + + Hide captions button + Captions button is hidden + Captions button is shown + + + Hide cast button + Cast button is hidden + Cast button is shown + + + Navigation buttons + Hide home button + Home button is hidden + Home button is shown + Hide Shorts button + Shorts button is hidden + Shorts button is shown + Hide subscriptions button + Home subscriptions is hidden + Home subscriptions is shown + Hide create button + 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 + + + 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 + + + Hide previous & next video buttons + Buttons are hidden + Buttons are shown + + + Hide album cards + Album cards are hidden + Album cards are shown + + + Hide breaking news + Breaking news are hidden + Breaking news are shown + + + Comments + 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 + Crowdfunding box is hidden + Crowdfunding box is shown + + + Hide end screen cards + End screen cards are hidden + End screen cards are shown + + + Hide filter bar + Hide in feed + Hidden in feed + Shown in feed + Hide in search + Hidden in search + Shown in search + 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 + Microphone button hidden + Microphone button shown + + + Disable ambient mode in fullscreen + Ambient mode disabled + Ambient mode enabled + + + Hide info cards + Info cards are hidden + Info cards are shown + + + Hide \'Load More\' button + Button is hidden + Button is shown + + + Video + + + Disable rolling number animations + Rolling numbers are not animated + Rolling numbers are animated + + + Hide seekbar in video player + Video player seekbar is hidden + Video player seekbar is shown + Hide seekbar in video thumbnails + Thumbnail seekbar is hidden + Thumbnail seekbar is shown + + + Shorts components + Hide Shorts in feed + Shorts are hidden + Shorts are shown + Hide join button + Join button is hidden + Join button is shown + Hide subscribe button + Subscribe button is hidden + Subscribe button is shown + Hide subscribe button when paused + Subscribe button is hidden + Subscribe button is shown + Hide thanks button + Thanks button is hidden + Thanks button is shown + Hide comments button + Comments button is hidden + Comments button is shown + Hide remix button + Remix button is hidden + Remix button is shown + Hide share button + Share button is hidden + Share button is shown + Hide info panel + Info panel is hidden + Info panel is shown + Hide channel bar + Channel bar is hidden + Channel bar is shown + Hide sound button + Sound button is hidden + Sound button is shown + Hide navigation bar + Navigation bar is hidden + Navigation bar is shown + Manage the visibility of Shorts components + + + Disable suggested video end screen + Suggested videos will be disabled + Suggested videos will be shown + + + Hide video timestamp + Timestamp is hidden + Timestamp is shown + + + Hide player popup panels + Player popup panels are hidden + Player popup panels are shown + + + Player overlay opacity + Opacity value between 0-100, where 0 is transparent + + + Return YouTube Dislike + Settings for Return YouTube Dislike + Hidden + Dislikes temporarily not available (API timed out) + Dislikes not available (status %d) + Dislikes not available (client API limit reached) + Dislikes not available (%s) + + Reload video to vote using ReturnYouTubeDislike + Return YouTube Dislike + Dislikes are shown + Dislikes are not shown + Show dislikes on Shorts + Dislikes shown on Shorts %s + Dislikes hidden on Shorts + Limitation: Dislikes may not appear in incognito mode + Dislikes as percentage + Dislikes shown as percentage + Dislikes shown as number + Compact like button + Like button styled for minimum width + Like button styled for best appearance + Show a toast if API is not available + Toast is shown if Return YouTube Dislike is not available + Toast is not shown if Return YouTube Dislike is not available + About + ReturnYouTubeDislike.com + Data is provided by the Return YouTube Dislike API. Tap here to learn more + ReturnYouTubeDislike API statistics of this device + API response time, average + API response time, minimum + API response time, maximum + API response time, last video + Dislikes temporarily not available - Client API rate limit in effect + API fetch votes, number of calls + No network calls made + %d network calls made + API fetch votes, number of timeouts + No + network calls timed out + %d network calls timed out + API client rate limits + No client rate limits encountered + Client rate limit encountered %d times + %d milliseconds + + + Enable wide search bar + Wide search bar is enabled + Wide search bar is disabled + + + Restore old seekbar thumbnails + 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 + Show voting button + Segment voting button is shown + Segment voting button is not shown + Use compact skip button + Skip button styled for minimum width + Skip button styled for best appearance + Automatically hide skip button + Skip button hides after a few seconds + Skip button displayed for entire segment + Show a toast when skipping automatically + Toast is shown when a segment is automatically skipped. Tap here to see an example + Toast is not shown. Tap here to see an example + Show video length without segments + Video length minus all segments, shown in parentheses next to the full video length + Full video length shown + Creating new segments + Show create new segment button + Create new segment button is shown + Create new segment button is not shown + Adjust new segment step + Number of milliseconds the time adjustment buttons move when creating new segments + Value must be a positive number + View guidelines + Guidelines contain rules and tips for creating new segments + Follow the guidelines + Read the SponsorBlock guidelines before creating new segments + Already read + Show me + General + Show a toast if API is not available + Toast is shown if SponsorBlock is not available + Toast is not shown if SponsorBlock is not available + Enable skip count tracking + Lets the SponsorBlock leaderboard know how much time is saved. A message is sent to the leaderboard each time a segment is skipped + Skip count tracking is not enabled + Minimum segment duration + Segments shorter than this value (in seconds) will not be shown or skipped + Your private user id + This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you + Private user id must be at least 30 characters long + Change API URL + The address SponsorBlock uses to make calls to the server. Do not change this unless you know what you\'re doing + API URL reset + API URL is invalid + API URL changed + Import/Export settings + Copy + Your SponsorBlock JSON configuration that can be imported/exported to ReVanced and other SponsorBlock platforms %s + This includes your private user id. Be sure to share this wisely + Settings imported successfully + Failed to import: %s + Failed to export: %s + Your settings contain a private SponsorBlock userid.\n\nYour user id is like a password and it should never be shared.\n + Do not show again + Change segment behavior + Sponsor + Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free shout-outs to causes/creators/websites/products they like + Unpaid/Self Promotion + Similar to \'Sponsor\' except for unpaid or self promotion. Includes sections about merchandise, donations, or information about who they collaborated with + Interaction Reminder (Subscribe) + A short reminder to like, subscribe or follow them in the middle of content. If it is long or about something specific, it should instead be under self promotion + Highlight + The part of the video that most people are looking for + Intermission/Intro Animation + An interval without actual content. Could be a pause, static frame, or repeating animation. Does not include transitions containing information + Endcards/Credits + Credits or when the YouTube endcards appear. Not for conclusions with information + Preview/Recap/Hook + Collection of clips that show what is coming up or what happened in the video or in other videos of a series, where all information is repeated elsewhere + Filler Tangent/Jokes + Tangential scenes added only for filler or humor that are not required to understand the main content of the video. Does not include segments providing context or background details + Music: Non-Music Section + Only for use in music videos. Sections of music videos without music, that aren\'t already covered by another category + Skip + Highlight + Skip sponsor + Skip promo + Skip interact + Skip to highlight + Skip intro + Skip intermission + Skip intermission + Skip outro + Skip preview + Skip preview + Skip recap + Skip filler + Skip non-music + Skip segment + Skipped sponsor + Skipped self promotion + Skipped annoying reminder + Skipped to highlight + Skipped intro + Skipped intermission + Skipped intermission + Skipped outro + Skipped preview + Skipped preview + Skipped recap + Skipped filler + Skipped a non-music section + Skipped unsubmitted segment + Skipped multiple segments + Skip automatically + Skip automatically once + Show a skip button + Show in seek bar + Disable + Unable to submit segment: %s + SponsorBlock is temporarily down + Unable to submit segment (status: %d %s) + Unable to submit segment.\nRate Limited (too many from the same user or IP) + Can\'t submit the segment: %s + Can\'t submit the segment.\nAlready exists + Segment submitted successfully + SponsorBlock temporarily not available + SponsorBlock temporarily not available (status %d) + SponsorBlock temporarily not available (API timed out) + Unable to vote for segment (API timed out) + Unable to vote for segment (status: %d %s) + Unable to vote for segment: %s + Upvote + Downvote + Change category + There are no segments to vote for + Choose the segment category + Category is disabled in settings. Enable category to submit. + New SponsorBlock segment + Set %02d:%02d:%03d as the start or end of a new segment? + start + end + now + Time the segment begins at + Time the segment ends at + Are the times correct? + The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds)\nIs it ready to submit? + Start must be before the end + Mark two locations on the time bar first + Preview the segment, and ensure it skips smoothly + Edit timing of segment manually + Do you want to edit the timing for the start or end of the segment? + Invalid time given + Stats + Stats temporarily not available (API is down) + Loading... + SponsorBlock is disabled + Your username: <b>%s</b> + Tap here to change your username + Unable to change username: Status: %d %s + Username successfully changed + Your reputation is <b>%.2f</b> + You\'ve created <b>%s</b> segments + SponsorBlock leaderboard + You\'ve saved people from <b>%s</b> segments + Tap here to see the global stats and top contributors + That\'s <b>%s</b> of their lives.<br>Tap here to see the leaderboard + You\'ve skipped <b>%s</b> segments + That\'s <b>%s</b> + Reset skipped segments counter? + %s hours %s minutes + %s minutes %s seconds + %s seconds + Color: + Color changed + Color reset + Invalid color code + Reset color + Reset + About + sponsor.ajay.app + Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms + + + Spoof app version + Version spoofed + 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.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 + Default + Home + Search + Subscriptions + Explore + Shorts + + + Disable resuming Shorts player + Shorts player will not resume on app startup + Shorts player will resume on app startup + + + Enable tablet layout + Settings related to the layout + Tablet layout is enabled + Tablet layout is disabled + Community posts do not show up on tablet layouts + + + Enable tablet mini player + Mini player is enabled + Mini player is disabled + + + Enable gradient loading screen + Loading screen will have a gradient background + Loading screen will have a solid background + + + Enable custom seekbar color + Custom seekbar color is shown + Original seekbar color is shown + Custom seekbar color + The color of the seekbar + Invalid seekbar color value. Using default value. + + + Alternative thumbnails + Thumbnails in use + Enable DeArrow thumbnails + Using DeArrow thumbnails + Not using DeArrow thumbnails + Show a toast if API is not available + Toast is shown if DeArrow is not available + Toast is not shown if DeArrow is not available + DeArrow API endpoint + The URL of the DeArrow thumbnail cache endpoint. Do not change this unless you know what you\'re doing + About DeArrow + DeArrow provides crowd-sourced thumbnails for YouTube videos. These thumbnails are often more relevant than those provided by YouTube. If enabled, video URLs will be sent to the API server and no other data is sent\n\nTap here to learn more about DeArrow + Enable still video captures + Using YouTube still video captures + Not using YouTube still video captures + Video time to take the still from + Beginning of video + Middle of video + End of video + Use fast still captures + Using medium quality still captures. Thumbnails will load faster, but live streams, unreleased, or very old videos may show blank thumbnails + 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 + + + Show ReVanced announcements + Announcements are shown on startup + Announcements are not shown on startup + Show announcements on startup + Failed connecting to announcements provider + + + Enable auto-repeat + Auto-repeat is enabled + Auto-repeat is disabled + + + Spoof device dimensions + Device dimensions spoofed + 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 + 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 + Turning off this setting will cause video playback issues. + Spoof app signature in feed + App signature spoofed\n\nSide effects include:\n• Feed videos are missing subtitles\n• Automatically played feed videos will show up in your watch history + App signature not spoofed for feed videos\n\nFeed videos will play for less than 1 minute beforeencountering playback issues + 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 + + + GmsCore Settings + Settings for GmsCore + + + Bypass URL redirects + URL redirects are bypassed + URL redirects are not bypassed + + + Open links in browser + Opening links externally + Opening links in app + + + Minimized playback + This setting can be found in Settings -> Background + + + Remove tracking query parameter + Tracking query parameter is removed from links + Tracking query parameter is not removed from links + + + Disable zoom haptics + Haptics are disabled + Haptics are enabled + + + Enable auto HDR brightness + Auto HDR brightness is enabled + Auto HDR brightness is disabled + + + Automatic quality + 2160p + 1440p + 1080p + 720p + 480p + 360p + 240p + 144p + Remember video quality changes + Quality changes apply to all videos + Quality changes only apply to the current video + Default video quality on Wi-Fi network + Default video quality on mobile network + mobile + wifi + Changed default %s quality to: %s + + + Custom playback speeds + Add or change the available playback speeds + Custom speeds must be less than %s Using default values. + Invalid custom playback speeds. Using default values. + + + Remember playback speed changes + Playback speed changes apply to all videos + Playback speed changes only apply to the current video + Default playback speed + Changed default speed to: %s + + + Restore old video quality menu + Old video quality menu is shown + Old video quality menu is not shown + + + Enable slide to seek + Slide to seek is enabled + Slide to seek is not enabled + + + + + Block audio ads + Audio ads are blocked + Audio ads are unblocked + + + %s is unavailable. Ads may show. Try switching to another ad block service in settings. + %s server returned an error. Ads may show. Try switching to another ad block service in settings. + Block embedded video ads + Embedded video ads are blocked + Embedded video ads are unblocked + Disabled + Luminous proxy + PurpleAdBlock proxy + + + Block video ads + Video ads are blocked + Video ads are unblocked + + + message deleted + Show deleted messages + Do not show deleted messages + Hide deleted messages behind a spoiler + Show deleted messages as crossed-out text + + + Automatically claim Channel Points + Channel Points are claimed automatically + Channel Points are not claimed automatically + + + Enable Twitch debug mode + Twitch debug mode is enabled (not recommended) + Twitch debug mode is disabled + + + ReVanced Settings + Debug logging + Debug logs are enabled + Debug logs are disabled + Ads + Ad blocking settings + Chat + Chat settings + Misc + Miscellaneous settings + General settings + Other settings + Client-side ads + Server-side surestream ads + + + \ No newline at end of file diff --git a/src/main/resources/alternativethumbnails/host/values/strings.xml b/src/main/resources/alternativethumbnails/host/values/strings.xml deleted file mode 100644 index 272bbc2f93..0000000000 --- a/src/main/resources/alternativethumbnails/host/values/strings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - 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 - \ No newline at end of file diff --git a/src/main/resources/change-header/revanced-borderless/drawable-hdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced-borderless/drawable-hdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..17e3539031 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-hdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-hdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced-borderless/drawable-hdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..d4998c5310 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-hdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-mdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced-borderless/drawable-mdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..167d4c9de6 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-mdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-mdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced-borderless/drawable-mdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..471e0079ce Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-mdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-xhdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced-borderless/drawable-xhdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..75bec79b4f Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-xhdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-xhdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced-borderless/drawable-xhdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..7f9f53fb00 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-xhdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-xxhdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced-borderless/drawable-xxhdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..76626d93c4 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-xxhdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-xxhdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced-borderless/drawable-xxhdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..701c08afa7 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-xxhdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-xxxhdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced-borderless/drawable-xxxhdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..cba9eef9d1 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-xxxhdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced-borderless/drawable-xxxhdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced-borderless/drawable-xxxhdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..6c21e375a2 Binary files /dev/null and b/src/main/resources/change-header/revanced-borderless/drawable-xxxhdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced/drawable-hdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced/drawable-hdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..8e95d04f22 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-hdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced/drawable-hdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced/drawable-hdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..3a71e6bb0d Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-hdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced/drawable-mdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced/drawable-mdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..4aff279ef6 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-mdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced/drawable-mdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced/drawable-mdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..48855aa3bd Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-mdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced/drawable-xhdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced/drawable-xhdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..ca652bf795 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-xhdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced/drawable-xhdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced/drawable-xhdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..6933bcca74 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-xhdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced/drawable-xxhdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced/drawable-xxhdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..0e79b3899a Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-xxhdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced/drawable-xxhdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced/drawable-xxhdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..43c273f486 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-xxhdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/change-header/revanced/drawable-xxxhdpi/yt_wordmark_header_dark.png b/src/main/resources/change-header/revanced/drawable-xxxhdpi/yt_wordmark_header_dark.png new file mode 100644 index 0000000000..59a8783e68 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-xxxhdpi/yt_wordmark_header_dark.png differ diff --git a/src/main/resources/change-header/revanced/drawable-xxxhdpi/yt_wordmark_header_light.png b/src/main/resources/change-header/revanced/drawable-xxxhdpi/yt_wordmark_header_light.png new file mode 100644 index 0000000000..263f3d9713 Binary files /dev/null and b/src/main/resources/change-header/revanced/drawable-xxxhdpi/yt_wordmark_header_light.png differ diff --git a/src/main/resources/copyvideourl/host/layout/youtube_controls_bottom_ui_container.xml b/src/main/resources/copyvideourl/host/layout/youtube_controls_bottom_ui_container.xml index 97ec1740f7..3a7cdd3efa 100644 --- a/src/main/resources/copyvideourl/host/layout/youtube_controls_bottom_ui_container.xml +++ b/src/main/resources/copyvideourl/host/layout/youtube_controls_bottom_ui_container.xml @@ -1,5 +1,5 @@ - - + + diff --git a/src/main/resources/copyvideourl/host/values/strings.xml b/src/main/resources/copyvideourl/host/values/strings.xml deleted file mode 100644 index 8452816c3f..0000000000 --- a/src/main/resources/copyvideourl/host/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - URL copied to clipboard - URL with timestamp copied - diff --git a/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/custom-branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png rename to src/main/resources/custom-branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png diff --git a/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/custom-branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png rename to src/main/resources/custom-branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png diff --git a/src/main/resources/branding/mipmap-hdpi/ic_launcher.png b/src/main/resources/custom-branding/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/main/resources/branding/mipmap-hdpi/ic_launcher.png rename to src/main/resources/custom-branding/mipmap-hdpi/ic_launcher.png diff --git a/src/main/resources/branding/mipmap-hdpi/ic_launcher_round.png b/src/main/resources/custom-branding/mipmap-hdpi/ic_launcher_round.png similarity index 100% rename from src/main/resources/branding/mipmap-hdpi/ic_launcher_round.png rename to src/main/resources/custom-branding/mipmap-hdpi/ic_launcher_round.png diff --git a/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/custom-branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png rename to src/main/resources/custom-branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png diff --git a/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/custom-branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png rename to src/main/resources/custom-branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png diff --git a/src/main/resources/branding/mipmap-mdpi/ic_launcher.png b/src/main/resources/custom-branding/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/main/resources/branding/mipmap-mdpi/ic_launcher.png rename to src/main/resources/custom-branding/mipmap-mdpi/ic_launcher.png diff --git a/src/main/resources/branding/mipmap-mdpi/ic_launcher_round.png b/src/main/resources/custom-branding/mipmap-mdpi/ic_launcher_round.png similarity index 100% rename from src/main/resources/branding/mipmap-mdpi/ic_launcher_round.png rename to src/main/resources/custom-branding/mipmap-mdpi/ic_launcher_round.png diff --git a/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/custom-branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png rename to src/main/resources/custom-branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png diff --git a/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/custom-branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png rename to src/main/resources/custom-branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png diff --git a/src/main/resources/branding/mipmap-xhdpi/ic_launcher.png b/src/main/resources/custom-branding/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/main/resources/branding/mipmap-xhdpi/ic_launcher.png rename to src/main/resources/custom-branding/mipmap-xhdpi/ic_launcher.png diff --git a/src/main/resources/branding/mipmap-xhdpi/ic_launcher_round.png b/src/main/resources/custom-branding/mipmap-xhdpi/ic_launcher_round.png similarity index 100% rename from src/main/resources/branding/mipmap-xhdpi/ic_launcher_round.png rename to src/main/resources/custom-branding/mipmap-xhdpi/ic_launcher_round.png diff --git a/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/custom-branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png rename to src/main/resources/custom-branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png diff --git a/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/custom-branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png rename to src/main/resources/custom-branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png diff --git a/src/main/resources/branding/mipmap-xxhdpi/ic_launcher.png b/src/main/resources/custom-branding/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/main/resources/branding/mipmap-xxhdpi/ic_launcher.png rename to src/main/resources/custom-branding/mipmap-xxhdpi/ic_launcher.png diff --git a/src/main/resources/branding/mipmap-xxhdpi/ic_launcher_round.png b/src/main/resources/custom-branding/mipmap-xxhdpi/ic_launcher_round.png similarity index 100% rename from src/main/resources/branding/mipmap-xxhdpi/ic_launcher_round.png rename to src/main/resources/custom-branding/mipmap-xxhdpi/ic_launcher_round.png diff --git a/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/custom-branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png rename to src/main/resources/custom-branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png diff --git a/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/custom-branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png similarity index 100% rename from src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png rename to src/main/resources/custom-branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png diff --git a/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher.png b/src/main/resources/custom-branding/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/main/resources/branding/mipmap-xxxhdpi/ic_launcher.png rename to src/main/resources/custom-branding/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher_round.png b/src/main/resources/custom-branding/mipmap-xxxhdpi/ic_launcher_round.png similarity index 100% rename from src/main/resources/branding/mipmap-xxxhdpi/ic_launcher_round.png rename to src/main/resources/custom-branding/mipmap-xxxhdpi/ic_launcher_round.png diff --git a/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml b/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml index 419845aa9a..b38a30b976 100644 --- a/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml +++ b/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml @@ -1,4 +1,4 @@ - + diff --git a/src/main/resources/downloads/host/values/strings.xml b/src/main/resources/downloads/host/values/strings.xml deleted file mode 100644 index dcdfd27532..0000000000 --- a/src/main/resources/downloads/host/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - is not installed. Please install it. - diff --git a/src/main/resources/gms/host/values/strings.xml b/src/main/resources/gms/host/values/strings.xml deleted file mode 100644 index 4697165ec5..0000000000 --- a/src/main/resources/gms/host/values/strings.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - GmsCore is not installed. Please install it. - GmsCore is failing to run. Please follow the "Don't kill my app" guide for GmsCore. - diff --git a/src/main/resources/returnyoutubedislike/host/values/strings.xml b/src/main/resources/returnyoutubedislike/host/values/strings.xml deleted file mode 100644 index 003547b34f..0000000000 --- a/src/main/resources/returnyoutubedislike/host/values/strings.xml +++ /dev/null @@ -1,60 +0,0 @@ - - Hidden - - Dislikes temporarily not available (API timed out) - Dislikes not available (status %d) - Dislikes not available (client API limit reached) - Dislikes not available (%s) - - - Reload video to vote using ReturnYouTubeDislike - - Return YouTube Dislike - Dislikes are shown - Dislikes are not shown - - Show dislikes on Shorts - Dislikes shown on Shorts %s - Dislikes hidden on Shorts - Limitation: Dislikes may not appear in incognito mode - - Dislikes as percentage - Dislikes shown as percentage - Dislikes shown as number - - Compact like button - Like button styled for minimum width - Like button styled for best appearance - - Show a toast if API is not available - Toast is shown if Return YouTube Dislike is not available - Toast is not shown if Return YouTube Dislike is not available - - About - ReturnYouTubeDislike.com - Data is provided by the Return YouTube Dislike API. Tap here to learn more. - - - ReturnYouTubeDislike API statistics of this device - - API response time, average - API response time, minimum - API response time, maximum - - API response time, last video - Dislikes temporarily not available - Client API rate limit in effect - - API fetch votes, number of calls - No network calls made - %d network calls made - - API fetch votes, number of timeouts - No network calls timed out - %d network calls timed out - - API client rate limits - No client rate limits encountered - Client rate limit encountered %d times - - %d milliseconds - diff --git a/src/main/resources/settings/host/values/strings.xml b/src/main/resources/settings/host/values/strings.xml deleted file mode 100644 index 75802473c6..0000000000 --- a/src/main/resources/settings/host/values/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - ReVanced - Do you wish to proceed? - Reset - - Import - Copy - ReVanced settings reset to default - Imported %d settings - Import failed: %s - diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml b/src/main/resources/sponsorblock/drawable/revanced_sb_adjust.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml rename to src/main/resources/sponsorblock/drawable/revanced_sb_adjust.xml diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml b/src/main/resources/sponsorblock/drawable/revanced_sb_compare.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_compare.xml rename to src/main/resources/sponsorblock/drawable/revanced_sb_compare.xml diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml b/src/main/resources/sponsorblock/drawable/revanced_sb_edit.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_edit.xml rename to src/main/resources/sponsorblock/drawable/revanced_sb_edit.xml diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml b/src/main/resources/sponsorblock/drawable/revanced_sb_logo.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_logo.xml rename to src/main/resources/sponsorblock/drawable/revanced_sb_logo.xml diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_publish.xml b/src/main/resources/sponsorblock/drawable/revanced_sb_publish.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_publish.xml rename to src/main/resources/sponsorblock/drawable/revanced_sb_publish.xml diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml b/src/main/resources/sponsorblock/drawable/revanced_sb_voting.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_voting.xml rename to src/main/resources/sponsorblock/drawable/revanced_sb_voting.xml diff --git a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml index 33a11b83b4..7c2d539183 100644 --- a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml +++ b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml @@ -1,7 +1,7 @@ + android:src="@drawable/revanced_sb_logo" /> + android:src="@drawable/revanced_sb_voting" /> diff --git a/src/main/resources/sponsorblock/host/values/strings.xml b/src/main/resources/sponsorblock/host/values/strings.xml deleted file mode 100644 index 62919d78fc..0000000000 --- a/src/main/resources/sponsorblock/host/values/strings.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - Enable SponsorBlock - SponsorBlock is a crowd-sourced system for skipping annoying parts of YouTube videos - - Appearance - Show voting button - Segment voting button is shown - Segment voting button is not shown - Use compact skip button - Skip button styled for minimum width - Skip button styled for best appearance - Automatically hide skip button - Skip button hides after a few seconds - Skip button displayed for entire segment - Show a toast when skipping automatically - Toast is shown when a segment is automatically skipped. Tap here to see an example - Toast is not shown. Tap here to see an example - Show video length without segments - Video length minus all segments, shown in parentheses next to the full video length - Full video length shown - - Creating new segments - Show create new segment button - Create new segment button is shown - Create new segment button is not shown - Adjust new segment step - Number of milliseconds the time adjustment buttons move when creating new segments - Value must be a positive number - View guidelines - Guidelines contain rules and tips for creating new segments - Follow the guidelines - Read the SponsorBlock guidelines before creating new segments - Already read - Show me - - General - Show a toast if API is not available - Toast is shown if SponsorBlock is not available - Toast is not shown if SponsorBlock is not available - Enable skip count tracking - Lets the SponsorBlock leaderboard know how much time is saved. A message is sent to the leaderboard each time a segment is skipped - Skip count tracking is not enabled - Minimum segment duration - Segments shorter than this value (in seconds) will not be shown or skipped - Your private user id - This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you - Private user id must be at least 30 characters long - Change API URL - The address SponsorBlock uses to make calls to the server. Do not change this unless you know what you\'re doing - API URL reset - API URL is invalid - API URL changed - Import/Export settings - Copy - Your SponsorBlock JSON configuration that can be imported/exported to ReVanced and other SponsorBlock platforms. %s - This includes your private user id. Be sure to share this wisely - Settings imported successfully - Failed to import: %s - Failed to export: %s - - Your settings contain a private SponsorBlock user id.\n\nYour user id is like a password and it should never be shared.\n - Do not show again - - Change segment behavior - Sponsor - Paid promotion, paid referrals and direct advertisements. Not for self-promotion or free shout-outs to causes/creators/websites/products they like - Unpaid/Self Promotion - Similar to \'Sponsor\' except for unpaid or self promotion. Includes sections about merchandise, donations, or information about who they collaborated with - Interaction Reminder (Subscribe) - A short reminder to like, subscribe or follow them in the middle of content. If it is long or about something specific, it should instead be under self promotion - Highlight - The part of the video that most people are looking for - Intermission/Intro Animation - An interval without actual content. Could be a pause, static frame, or repeating animation. Does not include transitions containing information - Endcards/Credits - Credits or when the YouTube endcards appear. Not for conclusions with information - Preview/Recap/Hook - Collection of clips that show what is coming up or what happened in the video or in other videos of a series, where all information is repeated elsewhere - Filler Tangent/Jokes - Tangential scenes added only for filler or humor that are not required to understand the main content of the video. Does not include segments providing context or background details - Music: Non-Music Section - Only for use in music videos. Sections of music videos without music, that aren\'t already covered by another category - - Skip - Highlight - Skip sponsor - Skip promo - Skip interact - Skip to highlight - Skip intro - Skip intermission - Skip intermission - Skip outro - Skip preview - Skip preview - Skip recap - Skip filler - Skip non-music - Skip segment - - Skipped sponsor - Skipped self promotion - Skipped annoying reminder - Skipped to highlight - Skipped intro - Skipped intermission - Skipped intermission - Skipped outro - Skipped preview - Skipped preview - Skipped recap - Skipped filler - Skipped a non-music section - Skipped unsubmitted segment - Skipped multiple segments - - Skip automatically - Skip automatically once - Show a skip button - Show in seek bar - Disable - - Unable to submit segment: %s - SponsorBlock is temporarily down - Unable to submit segment (status: %d %s) - Unable to submit segment.\nRate Limited (too many from the same user or IP) - Can\'t submit the segment: %s - Can\'t submit the segment.\nAlready exists - Segment submitted successfully - - SponsorBlock temporarily not available - SponsorBlock temporarily not available (status %d) - SponsorBlock temporarily not available (API timed out) - - Unable to vote for segment (API timed out) - Unable to vote for segment (status: %d %s) - Unable to vote for segment: %s - Upvote - Downvote - Change category - There are no segments to vote for - - Choose the segment category - Category is disabled in settings. Enable category to submit. - New SponsorBlock segment - Set %02d:%02d:%03d as the start or end of a new segment? - start - end - now - Time the segment begins at - Time the segment ends at - Are the times correct? - The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds)\nIs it ready to submit? - Start must be before the end - Mark two locations on the time bar first - Preview the segment, and ensure it skips smoothly - Edit timing of segment manually - Do you want to edit the timing for the start or end of the segment? - Invalid time given - - Stats - Stats temporarily not available (API is down) - Loading... - SponsorBlock is disabled - Your username: <b>%s</b> - Tap here to change your username - Unable to change username: Status: %d %s - Username successfully changed - Your reputation is <b>%.2f</b> - You\'ve created <b>%s</b> segments - SponsorBlock leaderboard - You\'ve saved people from <b>%s</b> segments - Tap here to see the global stats and top contributors - That\'s <b>%s</b> of their lives.<br>Tap here to see the leaderboard - You\'ve skipped <b>%s</b> segments - That\'s <b>%s</b> - Reset skipped segments counter? - %s hours %s minutes - %s minutes %s seconds - %s seconds - - Color: - Color changed - Color reset - Invalid color code - Reset color - - Reset - - About - sponsor.ajay.app - Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms - diff --git a/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml b/src/main/resources/sponsorblock/layout/revanced_sb_inline_sponsor_overlay.xml similarity index 66% rename from src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml rename to src/main/resources/sponsorblock/layout/revanced_sb_inline_sponsor_overlay.xml index 2c03855498..fb57b72524 100644 --- a/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml +++ b/src/main/resources/sponsorblock/layout/revanced_sb_inline_sponsor_overlay.xml @@ -1,9 +1,9 @@ - - - + android:src="@drawable/revanced_sb_adjust" /> + android:src="@drawable/revanced_sb_compare" /> + android:src="@drawable/revanced_sb_edit" /> + android:src="@drawable/revanced_sb_publish" /> \ No newline at end of file diff --git a/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml b/src/main/resources/sponsorblock/layout/revanced_sb_skip_sponsor_button.xml similarity index 82% rename from src/main/resources/sponsorblock/layout/skip_sponsor_button.xml rename to src/main/resources/sponsorblock/layout/revanced_sb_skip_sponsor_button.xml index 185960ec9e..b25987ff14 100644 --- a/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml +++ b/src/main/resources/sponsorblock/layout/revanced_sb_skip_sponsor_button.xml @@ -3,7 +3,7 @@ xmlns:yt="http://schemas.android.com/apk/res-auto"> - - \ No newline at end of file