diff --git a/CHANGELOG.md b/CHANGELOG.md index a2aff2d60..72da33559 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,247 @@ +# [2.197.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.4...v2.197.0-dev.5) (2023-11-18) + + +### Bug Fixes + +* Use a checked cast by reifying the generic type parameter ([f7a296e](https://github.com/ReVanced/revanced-patches/commit/f7a296e1f17d7bfb5fd303ee83cabd8d625781b9)) + + +### Features + +* **YouTube - Client spoof:** Add description to preference screen ([843a568](https://github.com/ReVanced/revanced-patches/commit/843a56854465fe2052977cd2a8f24ecb839f8d2a)) +* **YouTube - Hide layout components:** Add description to preference screen ([cc85441](https://github.com/ReVanced/revanced-patches/commit/cc854415e2311d4a06805a49a052fc8a16924739)) +* **YouTube - Hide layout components:** Hide description components ([38b8e44](https://github.com/ReVanced/revanced-patches/commit/38b8e44ec494e7dea24066dc2f5af578e01d58dc)) +* **YouTube - Navigation buttons:** Add description to preference screen ([14ea967](https://github.com/ReVanced/revanced-patches/commit/14ea9674c4e65ff2a92962222860b8035c7cda3f)) +* **YouTube - Seekbar:** Add description to preference screen ([ea6de49](https://github.com/ReVanced/revanced-patches/commit/ea6de498e3b002feeabf72d20059090db0be7f94)) +* **YouTube - Settings:** Sort preference screens below other types of preference ([9561db5](https://github.com/ReVanced/revanced-patches/commit/9561db50a82b0eeed07fe6541bc29a37f85b7caa)) +* **YouTube:** Support version `18.45.41` ([7c4f021](https://github.com/ReVanced/revanced-patches/commit/7c4f021f8c849dfc448c18ffc800da39576be617)) + +# [2.197.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.3...v2.197.0-dev.4) (2023-11-17) + + +### Features + +* **YouTube - Return YouTube Dislike:** Support version `18.43.45` and `18.44.41` ([#3260](https://github.com/ReVanced/revanced-patches/issues/3260)) ([70dee58](https://github.com/ReVanced/revanced-patches/commit/70dee584ed91b8f3dc7fe63c3d77fef6ed1dc745)) + +# [2.197.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.2...v2.197.0-dev.3) (2023-11-17) + + +### Features + +* **Android Widgets (Material U):** Remove `Unlock paid widgets` patch ([#3286](https://github.com/ReVanced/revanced-patches/issues/3286)) ([b44da1c](https://github.com/ReVanced/revanced-patches/commit/b44da1c7018c88d30be0849569837b4e17c68e0f)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-17) + + +### Bug Fixes + +* **YouTube - Disable resuming Shorts on startup:** Adjust patch name ([#3281](https://github.com/ReVanced/revanced-patches/issues/3281)) ([c332952](https://github.com/ReVanced/revanced-patches/commit/c3329527db739e6777fe8e77828e1226e4057b80)) +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([fb173e1](https://github.com/ReVanced/revanced-patches/commit/fb173e18afd5566a4ccdbb613810fa9646da9334)) + + +### Features + +* Add `Spoof SIM country` patch ([#3116](https://github.com/ReVanced/revanced-patches/issues/3116)) ([304a0d4](https://github.com/ReVanced/revanced-patches/commit/304a0d46bfee5ae96aaefee8f508eedd16004e36)) +* **Facebook:** Add `Hide story ads` patch ([#3257](https://github.com/ReVanced/revanced-patches/issues/3257)) ([1408c2e](https://github.com/ReVanced/revanced-patches/commit/1408c2e6283f4c48020d4305008a45f53b96b5cc)) +* **Twitch:** Support version `17.1.0` ([#3269](https://github.com/ReVanced/revanced-patches/issues/3269)) ([d88373b](https://github.com/ReVanced/revanced-patches/commit/d88373bf43a50198dec275301418435179bc822e)) +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([e205ac7](https://github.com/ReVanced/revanced-patches/commit/e205ac761d836047c52a4862132b6ea7d5a10b1b)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Player flyout menu:** Support version `18.43.45` and `18.44.41` ([#3263](https://github.com/ReVanced/revanced-patches/issues/3263)) ([fcbebf9](https://github.com/ReVanced/revanced-patches/commit/fcbebf90f350cb7653e14da33b703eb25098dd55)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([eee51a8](https://github.com/ReVanced/revanced-patches/commit/eee51a863a059c5073b2817e57059e072b72155d)) +* **YouTube - Vanced MicroG support:** Allow changing package name ([0c7490c](https://github.com/ReVanced/revanced-patches/commit/0c7490cbaf367d5029373096c41661c5112bfe53)) +* **YouTube Music - Vanced MicroG support:** Allow changing package name ([ede2d67](https://github.com/ReVanced/revanced-patches/commit/ede2d67b921480fbe496b551e43b190836d6bb72)) +* **YouTube:** Add `Enable slide to seek` patch ([68d10d4](https://github.com/ReVanced/revanced-patches/commit/68d10d4779d3545177fcf48f0aec237a2359b8b1)) +* **YouTube:** Add `Remove tracking query parameter` patch ([ddda3f6](https://github.com/ReVanced/revanced-patches/commit/ddda3f6e8cd919edaa891baee6597d2566e18e50)) +* **YouTube:** Bump compatibility to `18.38.45` ([9f19869](https://github.com/ReVanced/revanced-patches/commit/9f1986960cbaab84519d0685d1950764c16d08a5)) +* **YouTube:** Bump compatibility to `18.44.41` ([384a0a6](https://github.com/ReVanced/revanced-patches/commit/384a0a67c52d7d342afae491388199aca6b78b4d)) +* **YouTube:** Support version `18.43.45` for `Playback speed` and `Restore old video quality menu` ([c5236f8](https://github.com/ReVanced/revanced-patches/commit/c5236f812e1e362e4d03885b0950385e360bbff8)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-16) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([fb173e1](https://github.com/ReVanced/revanced-patches/commit/fb173e18afd5566a4ccdbb613810fa9646da9334)) + + +### Features + +* Add `Spoof SIM country` patch ([#3116](https://github.com/ReVanced/revanced-patches/issues/3116)) ([304a0d4](https://github.com/ReVanced/revanced-patches/commit/304a0d46bfee5ae96aaefee8f508eedd16004e36)) +* **Facebook:** Add `Hide story ads` patch ([#3257](https://github.com/ReVanced/revanced-patches/issues/3257)) ([1408c2e](https://github.com/ReVanced/revanced-patches/commit/1408c2e6283f4c48020d4305008a45f53b96b5cc)) +* **Twitch:** Support version `17.1.0` ([#3269](https://github.com/ReVanced/revanced-patches/issues/3269)) ([d88373b](https://github.com/ReVanced/revanced-patches/commit/d88373bf43a50198dec275301418435179bc822e)) +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([e205ac7](https://github.com/ReVanced/revanced-patches/commit/e205ac761d836047c52a4862132b6ea7d5a10b1b)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Player flyout menu:** Support version `18.43.45` and `18.44.41` ([#3263](https://github.com/ReVanced/revanced-patches/issues/3263)) ([fcbebf9](https://github.com/ReVanced/revanced-patches/commit/fcbebf90f350cb7653e14da33b703eb25098dd55)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([eee51a8](https://github.com/ReVanced/revanced-patches/commit/eee51a863a059c5073b2817e57059e072b72155d)) +* **YouTube - Vanced MicroG support:** Allow changing package name ([0c7490c](https://github.com/ReVanced/revanced-patches/commit/0c7490cbaf367d5029373096c41661c5112bfe53)) +* **YouTube Music - Vanced MicroG support:** Allow changing package name ([ede2d67](https://github.com/ReVanced/revanced-patches/commit/ede2d67b921480fbe496b551e43b190836d6bb72)) +* **YouTube:** Add `Enable slide to seek` patch ([68d10d4](https://github.com/ReVanced/revanced-patches/commit/68d10d4779d3545177fcf48f0aec237a2359b8b1)) +* **YouTube:** Add `Remove tracking query parameter` patch ([ddda3f6](https://github.com/ReVanced/revanced-patches/commit/ddda3f6e8cd919edaa891baee6597d2566e18e50)) +* **YouTube:** Bump compatibility to `18.38.45` ([9f19869](https://github.com/ReVanced/revanced-patches/commit/9f1986960cbaab84519d0685d1950764c16d08a5)) +* **YouTube:** Bump compatibility to `18.44.41` ([384a0a6](https://github.com/ReVanced/revanced-patches/commit/384a0a67c52d7d342afae491388199aca6b78b4d)) +* **YouTube:** Support version `18.43.45` for `Playback speed` and `Restore old video quality menu` ([c5236f8](https://github.com/ReVanced/revanced-patches/commit/c5236f812e1e362e4d03885b0950385e360bbff8)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-15) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([fb173e1](https://github.com/ReVanced/revanced-patches/commit/fb173e18afd5566a4ccdbb613810fa9646da9334)) + + +### Features + +* Add `Spoof SIM country` patch ([#3116](https://github.com/ReVanced/revanced-patches/issues/3116)) ([304a0d4](https://github.com/ReVanced/revanced-patches/commit/304a0d46bfee5ae96aaefee8f508eedd16004e36)) +* **Facebook:** Add `Hide story ads` patch ([#3257](https://github.com/ReVanced/revanced-patches/issues/3257)) ([1408c2e](https://github.com/ReVanced/revanced-patches/commit/1408c2e6283f4c48020d4305008a45f53b96b5cc)) +* **Twitch:** Support version `17.1.0` ([#3269](https://github.com/ReVanced/revanced-patches/issues/3269)) ([d88373b](https://github.com/ReVanced/revanced-patches/commit/d88373bf43a50198dec275301418435179bc822e)) +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([e205ac7](https://github.com/ReVanced/revanced-patches/commit/e205ac761d836047c52a4862132b6ea7d5a10b1b)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Player flyout menu:** Support version `18.43.45` and `18.44.41` ([#3263](https://github.com/ReVanced/revanced-patches/issues/3263)) ([fcbebf9](https://github.com/ReVanced/revanced-patches/commit/fcbebf90f350cb7653e14da33b703eb25098dd55)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([eee51a8](https://github.com/ReVanced/revanced-patches/commit/eee51a863a059c5073b2817e57059e072b72155d)) +* **YouTube:** Add `Enable slide to seek` patch ([68d10d4](https://github.com/ReVanced/revanced-patches/commit/68d10d4779d3545177fcf48f0aec237a2359b8b1)) +* **YouTube:** Add `Remove tracking query parameter` patch ([ddda3f6](https://github.com/ReVanced/revanced-patches/commit/ddda3f6e8cd919edaa891baee6597d2566e18e50)) +* **YouTube:** Bump compatibility to `18.38.45` ([9f19869](https://github.com/ReVanced/revanced-patches/commit/9f1986960cbaab84519d0685d1950764c16d08a5)) +* **YouTube:** Bump compatibility to `18.44.41` ([384a0a6](https://github.com/ReVanced/revanced-patches/commit/384a0a67c52d7d342afae491388199aca6b78b4d)) +* **YouTube:** Support version `18.43.45` for `Playback speed` and `Restore old video quality menu` ([c5236f8](https://github.com/ReVanced/revanced-patches/commit/c5236f812e1e362e4d03885b0950385e360bbff8)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-13) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([fb173e1](https://github.com/ReVanced/revanced-patches/commit/fb173e18afd5566a4ccdbb613810fa9646da9334)) + + +### Features + +* Add `Spoof SIM country` patch ([#3116](https://github.com/ReVanced/revanced-patches/issues/3116)) ([304a0d4](https://github.com/ReVanced/revanced-patches/commit/304a0d46bfee5ae96aaefee8f508eedd16004e36)) +* **Facebook:** Add `Hide story ads` patch ([#3257](https://github.com/ReVanced/revanced-patches/issues/3257)) ([1408c2e](https://github.com/ReVanced/revanced-patches/commit/1408c2e6283f4c48020d4305008a45f53b96b5cc)) +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([e205ac7](https://github.com/ReVanced/revanced-patches/commit/e205ac761d836047c52a4862132b6ea7d5a10b1b)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Player flyout menu:** Support version `18.43.45` and `18.44.41` ([#3263](https://github.com/ReVanced/revanced-patches/issues/3263)) ([fcbebf9](https://github.com/ReVanced/revanced-patches/commit/fcbebf90f350cb7653e14da33b703eb25098dd55)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([eee51a8](https://github.com/ReVanced/revanced-patches/commit/eee51a863a059c5073b2817e57059e072b72155d)) +* **YouTube:** Add `Enable slide to seek` patch ([68d10d4](https://github.com/ReVanced/revanced-patches/commit/68d10d4779d3545177fcf48f0aec237a2359b8b1)) +* **YouTube:** Add `Remove tracking query parameter` patch ([ddda3f6](https://github.com/ReVanced/revanced-patches/commit/ddda3f6e8cd919edaa891baee6597d2566e18e50)) +* **YouTube:** Bump compatibility to `18.38.45` ([9f19869](https://github.com/ReVanced/revanced-patches/commit/9f1986960cbaab84519d0685d1950764c16d08a5)) +* **YouTube:** Bump compatibility to `18.44.41` ([384a0a6](https://github.com/ReVanced/revanced-patches/commit/384a0a67c52d7d342afae491388199aca6b78b4d)) +* **YouTube:** Support version `18.43.45` for `Playback speed` and `Restore old video quality menu` ([c5236f8](https://github.com/ReVanced/revanced-patches/commit/c5236f812e1e362e4d03885b0950385e360bbff8)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-12) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([fb173e1](https://github.com/ReVanced/revanced-patches/commit/fb173e18afd5566a4ccdbb613810fa9646da9334)) + + +### Features + +* Add `Spoof SIM country` patch ([#3116](https://github.com/ReVanced/revanced-patches/issues/3116)) ([304a0d4](https://github.com/ReVanced/revanced-patches/commit/304a0d46bfee5ae96aaefee8f508eedd16004e36)) +* **Facebook:** Add `Hide story ads` patch ([#3257](https://github.com/ReVanced/revanced-patches/issues/3257)) ([1408c2e](https://github.com/ReVanced/revanced-patches/commit/1408c2e6283f4c48020d4305008a45f53b96b5cc)) +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([e205ac7](https://github.com/ReVanced/revanced-patches/commit/e205ac761d836047c52a4862132b6ea7d5a10b1b)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([eee51a8](https://github.com/ReVanced/revanced-patches/commit/eee51a863a059c5073b2817e57059e072b72155d)) +* **YouTube:** Add `Enable slide to seek` patch ([68d10d4](https://github.com/ReVanced/revanced-patches/commit/68d10d4779d3545177fcf48f0aec237a2359b8b1)) +* **YouTube:** Add `Remove tracking query parameter` patch ([ddda3f6](https://github.com/ReVanced/revanced-patches/commit/ddda3f6e8cd919edaa891baee6597d2566e18e50)) +* **YouTube:** Bump compatibility to `18.38.45` ([9f19869](https://github.com/ReVanced/revanced-patches/commit/9f1986960cbaab84519d0685d1950764c16d08a5)) +* **YouTube:** Bump compatibility to `18.44.41` ([384a0a6](https://github.com/ReVanced/revanced-patches/commit/384a0a67c52d7d342afae491388199aca6b78b4d)) +* **YouTube:** Support version `18.43.45` for `Playback speed` and `Restore old video quality menu` ([c5236f8](https://github.com/ReVanced/revanced-patches/commit/c5236f812e1e362e4d03885b0950385e360bbff8)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-12) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([fb173e1](https://github.com/ReVanced/revanced-patches/commit/fb173e18afd5566a4ccdbb613810fa9646da9334)) + + +### Features + +* Add `Spoof SIM country` patch ([#3116](https://github.com/ReVanced/revanced-patches/issues/3116)) ([304a0d4](https://github.com/ReVanced/revanced-patches/commit/304a0d46bfee5ae96aaefee8f508eedd16004e36)) +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([e205ac7](https://github.com/ReVanced/revanced-patches/commit/e205ac761d836047c52a4862132b6ea7d5a10b1b)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([eee51a8](https://github.com/ReVanced/revanced-patches/commit/eee51a863a059c5073b2817e57059e072b72155d)) +* **YouTube:** Add `Enable slide to seek` patch ([68d10d4](https://github.com/ReVanced/revanced-patches/commit/68d10d4779d3545177fcf48f0aec237a2359b8b1)) +* **YouTube:** Add `Remove tracking query parameter` patch ([ddda3f6](https://github.com/ReVanced/revanced-patches/commit/ddda3f6e8cd919edaa891baee6597d2566e18e50)) +* **YouTube:** Bump compatibility to `18.38.45` ([9f19869](https://github.com/ReVanced/revanced-patches/commit/9f1986960cbaab84519d0685d1950764c16d08a5)) +* **YouTube:** Bump compatibility to `18.44.41` ([384a0a6](https://github.com/ReVanced/revanced-patches/commit/384a0a67c52d7d342afae491388199aca6b78b4d)) +* **YouTube:** Support version `18.43.45` for `Playback speed` and `Restore old video quality menu` ([c5236f8](https://github.com/ReVanced/revanced-patches/commit/c5236f812e1e362e4d03885b0950385e360bbff8)) + +# [2.197.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.197.0-dev.1...v2.197.0-dev.2) (2023-11-12) + + +### Bug Fixes + +* **YouTube - Hide layout components:** Reduce false positives when hiding mix playlists ([aac30ad](https://github.com/ReVanced/revanced-patches/commit/aac30ad717df02af87f2d65edddac8119cb262e9)) + + +### Features + +* **YouTube - Bypass URL redirects:** Support version `18.43.45` ([8935955](https://github.com/ReVanced/revanced-patches/commit/89359550c087e457a3fa5ad924daae0735cfad55)) +* **YouTube - Hide timestamp:** Support version `18.43.45` ([9180d4f](https://github.com/ReVanced/revanced-patches/commit/9180d4f5c3d4a50f412b37af69d61aafce5ffc07)) +* **YouTube - Navigation buttons:** Support version `18.43.45` ([e21286e](https://github.com/ReVanced/revanced-patches/commit/e21286e4d76323adb24ca8112a4ce03bfab98d60)) +* **YouTube - Seekbar tapping:** Support version `18.43.45` ([7828b14](https://github.com/ReVanced/revanced-patches/commit/7828b1425bd766db79fa8b28f002c75ff8d62cdd)) +* **YouTube:** Add `Enable slide to seek` patch ([a82fa35](https://github.com/ReVanced/revanced-patches/commit/a82fa35dd8dff30fabdc5f91c48a95234ed5d055)) +* **YouTube:** Add `Remove tracking query parameter` patch ([a353934](https://github.com/ReVanced/revanced-patches/commit/a3539348ce488f1effc88e62a1e0bd1a3635a2bd)) +* **YouTube:** Bump compatibility to `18.38.45` ([f743491](https://github.com/ReVanced/revanced-patches/commit/f7434910ad860e92f6c8d71a1fcd063ae075b704)) +* **YouTube:** Bump compatibility to `18.44.41` ([5490f58](https://github.com/ReVanced/revanced-patches/commit/5490f58974b6d5a0af145f3518756d736566adc7)) +* **YouTube:** Support version `18.43.45` for `Playback speed failed` and `Restore old video quality menu` ([b5e3263](https://github.com/ReVanced/revanced-patches/commit/b5e326348a581f343a4f05ae7a8c822bc6c90313)) + +# [2.197.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v2.196.1-dev.6...v2.197.0-dev.1) (2023-11-12) + + +### Features + +* **Twitch:** Support version `17.0.0` ([#3250](https://github.com/ReVanced/revanced-patches/issues/3250)) ([9c103ac](https://github.com/ReVanced/revanced-patches/commit/9c103acb94b8d7d2858441300bd297fedbacbb40)) + +## [2.196.1-dev.6](https://github.com/ReVanced/revanced-patches/compare/v2.196.1-dev.5...v2.196.1-dev.6) (2023-11-11) + + +### Bug Fixes + +* **YouTube - Client spoof:** Fix low resolution precise seeking thumbnails ([#3249](https://github.com/ReVanced/revanced-patches/issues/3249)) ([0cb41ef](https://github.com/ReVanced/revanced-patches/commit/0cb41efa067d74b873167718b25893cb2e1dd240)) + +## [2.196.1-dev.5](https://github.com/ReVanced/revanced-patches/compare/v2.196.1-dev.4...v2.196.1-dev.5) (2023-11-10) + + +### Bug Fixes + +* **Remove screenshot restriction:** Improve reliability ([#2938](https://github.com/ReVanced/revanced-patches/issues/2938)) ([6b7cb7b](https://github.com/ReVanced/revanced-patches/commit/6b7cb7bd38348dbe4a56385356df6ed97e81c319)) + +## [2.196.1-dev.4](https://github.com/ReVanced/revanced-patches/compare/v2.196.1-dev.3...v2.196.1-dev.4) (2023-11-09) + + +### Bug Fixes + +* **YouTube - SponsorBlock:** Rename "Preview/Recap" category to "Preview/Recap/Hook" ([#3245](https://github.com/ReVanced/revanced-patches/issues/3245)) ([2cd2453](https://github.com/ReVanced/revanced-patches/commit/2cd2453658622f369b6449d5c8c33326384c2679)) + +## [2.196.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v2.196.1-dev.2...v2.196.1-dev.3) (2023-11-06) + + +### Bug Fixes + +* **Nyx Music Plaer - Unlock pro:** Constrain to last working version ([96d24a3](https://github.com/ReVanced/revanced-patches/commit/96d24a3e2ef6bd323aa44a05aaf122683898e90a)) + +## [2.196.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v2.196.1-dev.1...v2.196.1-dev.2) (2023-11-06) + + +### Bug Fixes + +* **YouTube:** Rename `Restore old seekbar thumbnails` and `Restore old quality menu` ([#3235](https://github.com/ReVanced/revanced-patches/issues/3235)) ([7e3ffc8](https://github.com/ReVanced/revanced-patches/commit/7e3ffc88631da47a032cb29a4a30fd8f5679542d)) + +## [2.196.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v2.196.0...v2.196.1-dev.1) (2023-11-06) + + +### Bug Fixes + +* **YouTube - Theme:** Use consistent patch option descriptions ([#3231](https://github.com/ReVanced/revanced-patches/issues/3231)) ([c84a940](https://github.com/ReVanced/revanced-patches/commit/c84a94075ecba11e826f0b311283ef530563fe93)) + # [2.196.0](https://github.com/ReVanced/revanced-patches/compare/v2.195.0...v2.196.0) (2023-11-04) diff --git a/gradle.properties b/gradle.properties index 9865ff8e5..0bc831f3e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.parallel = true org.gradle.caching = true kotlin.code.style = official -version = 2.196.0 +version = 2.197.0-dev.5 diff --git a/patches.json b/patches.json index 76049d605..8268d45eb 100644 --- a/patches.json +++ b/patches.json @@ -1 +1 @@ -[{"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":"Disable mandatory login","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock plus","description":null,"compatiblePackages":[{"name":"com.microblink.photomath","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device ID","description":"Spoofs device ID to mitigate manual bans by developers.","compatiblePackages":[{"name":"com.microblink.photomath","versions":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":"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":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","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":"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":"Settings","description":"Adds ReVanced settings to TikTok.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["30.8.4"]},{"name":"com.zhiliaoapp.musically","versions":["30.8.4"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable login requirement","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Fix Google login","description":"Allows logging in with a Google account.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Enables the playback speed option for all videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"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":["30.8.4"]},{"name":"com.zhiliaoapp.musically","versions":["30.8.4"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Feed filter","description":"Filters tiktok videos: removing ads, removing livestreams.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["30.8.4"]},{"name":"com.zhiliaoapp.musically","versions":["30.8.4"]}],"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":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.awedea.nyx","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":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false},{"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":false},{"key":"accentPressedColor","default":"#ff169c46","values":null,"title":"Pressed accent for the dark theme","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":false}]},{"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":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","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":"Hide ads","description":null,"compatiblePackages":[{"name":"jp.pxv.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Sanitize sharing links","description":"Removes (tracking) query parameters from the URLs when sharing links.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":["5.4.0","5.4.1","5.4.2","6.0.1","6.0.2","6.0.4","6.0.6","6.1.1"]}],"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":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","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\u0027s.","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\u0027s.","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":"Disable Sync for Lemmy bottom sheet","description":"Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":["v23.06.30-13:39"]},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","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":"o.o.joey","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","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\u0027s.","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\u0027s.","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":"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":"Unlock pro","description":null,"compatiblePackages":[{"name":"ginlemon.iconpackstudio","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":"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 pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","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":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","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":"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 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":"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 Twitter Blue with the user\u0027s Material You palette.","compatiblePackages":[{"name":"com.twitter.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"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":"Pro unlock","description":null,"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}],"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":"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":"Always autorepeat","description":"Always repeats the playing video again.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Vanced MicroG support","description":"Allows YouTube to run without root and under a different package name with Vanced MicroG.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Enables minimized and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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":"Client spoof","description":"Spoofs the client to allow playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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":"Bypass URL redirects","description":"Bypass URL redirects and open the original URL directly.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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":"HDR auto brightness","description":"Makes the brightness of HDR videos follow the system default.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds custom playback speeds and ability to remember the playback speed you chose in the video playback speed flyout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Old video quality menu","description":"Shows the old video quality with the advanced video quality options instead of the new one.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds volume and brightness swipe controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"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":"Custom branding","description":"Changes the app icon and name 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":"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":"Spoof app version","description":"Tricks YouTube into thinking you are running an older version of the app. One of the side effects also includes restoring the old UI.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.37.36","18.38.44"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Hides components from YouTube Shorts.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Hides player flyout menu items.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide email address","description":"Hides the email address in the account switcher.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Hides info cards in videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Hides the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Hides timestamp in video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Hides components related to comments.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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":"Hide video action buttons","description":"Adds the options to hide action buttons under a video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Hides the captions button on video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide player buttons","description":"Adds the option to hide video player previous and next buttons.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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":"Navigation buttons","description":"Adds options to hide or change navigation buttons.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"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.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Enables the tablet mini player layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[{"key":"darkThemeBackgroundColor","default":"@android:color/black","values":{"Amoled black":"@android:color/black","Material You":"@android:color/system_neutral1_900","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 or a color resource reference.","required":false}]},{"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Enable old seekbar thumbnails","description":"Enables the old seekbar thumbnails that appear above the seekbar instead of in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable Shorts on startup","description":"Disables playing YouTube Shorts when launching YouTube.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable player popup panels","description":"Disables panels from appearing automatically when going into fullscreen (playlist or live chat).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Video ads","description":"Removes ads in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44"]}],"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":"Vanced MicroG support","description":"Allows YouTube Music to run without root and under a different package name.","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":"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":"Permanent repeat","description":"Permanently remember your repeating preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Permanent shuffle","description":"Permanently remember your shuffle preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"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":"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":"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":"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":"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 paid widgets","description":"Unlocks paid widgets of the app","compatiblePackages":[{"name":"com.dci.dev.androidtwelvewidgets","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":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","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":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"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":"Settings","description":"Adds settings menu to Twitch.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":null}],"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":"Auto claim channel points","description":"Automatically claim Channel Points.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0"]}],"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"]}],"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"]}],"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"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Change package name","description":"Appends \".revanced\" to the package name by default.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"packageName","default":"Default","values":{"Default":"Default"},"title":"Package name","description":"The name of the package to rename the app to.","required":true}]},{"name":"Enable Android debugging","description":"Enables Android debugging capabilities. This can slow down the app.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Override certificate pinning","description":"Overrides certificate pinning, allowing to inspect traffic via a proxy.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"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":"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":"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":"com.wakdev.apps.nfctools.se","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":"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":"Disable mandatory login","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock premium","description":null,"compatiblePackages":[{"name":"com.adobe.lrmobile","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock plus","description":null,"compatiblePackages":[{"name":"com.microblink.photomath","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof device ID","description":"Spoofs device ID to mitigate manual bans by developers.","compatiblePackages":[{"name":"com.microblink.photomath","versions":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":"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":"Disable ads","description":null,"compatiblePackages":[{"name":"com.myprog.hexedit","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":"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":"Settings","description":"Adds ReVanced settings to TikTok.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["30.8.4"]},{"name":"com.zhiliaoapp.musically","versions":["30.8.4"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable login requirement","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Fix Google login","description":"Allows logging in with a Google account.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Enables the playback speed option for all videos.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"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":["30.8.4"]},{"name":"com.zhiliaoapp.musically","versions":["30.8.4"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Feed filter","description":"Filters tiktok videos: removing ads, removing livestreams.","compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":null},{"name":"com.zhiliaoapp.musically","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":null,"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["30.8.4"]},{"name":"com.zhiliaoapp.musically","versions":["30.8.4"]}],"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":"Hide ads","description":null,"compatiblePackages":[{"name":"com.nis.app","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":"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":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false},{"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":false},{"key":"accentPressedColor","default":"#ff169c46","values":null,"title":"Pressed accent for the dark theme","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":false}]},{"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":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.vanced.android.youtube","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":"Hide ads","description":null,"compatiblePackages":[{"name":"jp.pxv.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Sanitize sharing links","description":"Removes (tracking) query parameters from the URLs when sharing links.","compatiblePackages":[{"name":"com.reddit.frontpage","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","compatiblePackages":[{"name":"ml.docilealligator.infinityforreddit","versions":["5.4.0","5.4.1","5.4.2","6.0.1","6.0.2","6.0.4","6.0.6","6.1.1"]}],"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":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","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\u0027s.","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\u0027s.","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":"Disable Sync for Lemmy bottom sheet","description":"Disables the bottom sheet at the startup that asks you to signup to \"Sync for Lemmy\".","compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":["v23.06.30-13:39"]},{"name":"com.laurencedawson.reddit_sync.pro","versions":null},{"name":"com.laurencedawson.reddit_sync.dev","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable ads","description":null,"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","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":"o.o.joey","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Spoof client","description":"Restores functionality of the app by using custom client ID\u0027s.","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\u0027s.","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\u0027s.","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":"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":"Unlock pro","description":null,"compatiblePackages":[{"name":"ginlemon.iconpackstudio","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":"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 pro","description":null,"compatiblePackages":[{"name":"com.ithebk.expensemanager","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":"Unlock pro","description":"Unlocks pro features.","compatiblePackages":[{"name":"com.vsco.cam","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":"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 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":"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 Twitter Blue with the user\u0027s Material You palette.","compatiblePackages":[{"name":"com.twitter.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":"Unlock pro","description":"Unlocks all pro features.","compatiblePackages":[{"name":"co.windyapp.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Show on lockscreen","description":"Shows student id and student ticket on lockscreen.","compatiblePackages":[{"name":"de.tudortmund.app","versions":null}],"use":true,"requiresIntegrations":true,"options":[]},{"name":"Pro unlock","description":null,"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}],"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":"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":"Always autorepeat","description":"Always repeats the playing video again.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remove tracking query parameter","description":"Remove the tracking query parameter from links.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Vanced MicroG support","description":"Allows YouTube to run without root and under a different package name with Vanced MicroG.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Minimized playback","description":"Enables minimized and background playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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":"Client spoof","description":"Spoofs the client to allow playback.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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":"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"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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":"HDR auto brightness","description":"Makes the brightness of HDR videos follow the system default.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Playback speed","description":"Adds custom playback speeds and ability to remember the playback speed you chose in the video playback speed flyout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Remember video quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Swipe controls","description":"Adds volume and brightness swipe controls.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Enable slide to seek","description":"Enable slide to seek instead of playing at 2x speed.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.43.45","18.44.41","18.45.41"]}],"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"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"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":"Custom branding","description":"Changes the app icon and name 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":"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":"Spoof app version","description":"Tricks YouTube into thinking you are running an older version of the app. One of the side effects also includes restoring the old UI.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.45.41"]}],"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"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide Shorts components","description":"Hides components from YouTube Shorts.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Player flyout menu","description":"Hides player flyout menu items.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide email address","description":"Hides the email address in the account switcher.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide info cards","description":"Hides info cards in videos.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide seekbar","description":"Hides the seekbar.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide timestamp","description":"Hides timestamp in video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Comments","description":"Hides components related to comments.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide endscreen cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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":"Hide video action buttons","description":"Adds the options to hide action buttons under a video.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide captions button","description":"Hides the captions button on video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide player buttons","description":"Adds the option to hide video player previous and next buttons.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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":"Navigation buttons","description":"Adds options to hide or change navigation buttons.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"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.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Tablet mini player","description":"Enables the tablet mini player layout.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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"]}],"use":true,"requiresIntegrations":false,"options":[{"key":"darkThemeBackgroundColor","default":"@android:color/black","values":{"Amoled black":"@android:color/black","Material You":"@android:color/system_neutral1_900","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":"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":false,"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"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"SponsorBlock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Disable player popup panels","description":"Disables panels from appearing automatically when going into fullscreen (playlist or live chat).","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Video ads","description":"Removes ads in the video player.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Hide ads","description":"Removes general ads.","compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35","18.20.39","18.23.35","18.29.38","18.32.39","18.37.36","18.38.44","18.43.45","18.44.41","18.45.41"]}],"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":"Vanced MicroG support","description":"Allows YouTube Music to run without root and under a different package name.","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":"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":"Permanent repeat","description":"Permanently remember your repeating preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"Permanent shuffle","description":"Permanently remember your shuffle preference even if the playlist ends or another track is played.","compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":null}],"use":false,"requiresIntegrations":false,"options":[]},{"name":"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":"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":"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":"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":"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":"Remove ads","description":null,"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"com.candylink.openvpn","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":"Unlock premium","description":null,"compatiblePackages":[{"name":"io.yuka.android","versions":null}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Unlock pro","description":null,"compatiblePackages":[{"name":"tv.trakt.trakt","versions":["1.1.1"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"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":"Settings","description":"Adds settings menu to Twitch.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":null}],"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":"Auto claim channel points","description":"Automatically claim Channel Points.","compatiblePackages":[{"name":"tv.twitch.android.app","versions":["15.4.1","16.1.0","17.0.0","17.1.0"]}],"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","17.0.0","17.1.0"]}],"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","17.0.0","17.1.0"]}],"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","17.0.0","17.1.0"]}],"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","17.0.0","17.1.0"]}],"use":true,"requiresIntegrations":false,"options":[]},{"name":"Export all activities","description":"Makes all app activities exportable.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Change package name","description":"Appends \".revanced\" to the package name by default.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[{"key":"packageName","default":"Default","values":{"Default":"Default"},"title":"Package name","description":"The name of the package to rename the app to.","required":true}]},{"name":"Enable Android debugging","description":"Enables Android debugging capabilities. This can slow down the app.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"Override certificate pinning","description":"Overrides certificate pinning, allowing to inspect traffic via a proxy.","compatiblePackages":null,"use":false,"requiresIntegrations":false,"options":[]},{"name":"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":null,"title":"Network ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent of the MCC (Mobile Country Code) of the current registered operator or the cell nearby.","required":false},{"key":"simCountryIso","default":null,"values":null,"title":"Sim ISO Country Code","description":"ISO-3166-1 alpha-2 country code equivalent for the SIM provider\u0027s country code.","required":false}]},{"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":"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":"com.wakdev.apps.nfctools.se","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 diff --git a/src/main/kotlin/app/revanced/extensions/Extensions.kt b/src/main/kotlin/app/revanced/extensions/Extensions.kt index 7aed580f0..309dc5396 100644 --- a/src/main/kotlin/app/revanced/extensions/Extensions.kt +++ b/src/main/kotlin/app/revanced/extensions/Extensions.kt @@ -8,7 +8,10 @@ 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 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 import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction +import com.android.tools.smali.dexlib2.iface.reference.Reference import com.android.tools.smali.dexlib2.util.MethodUtil import org.w3c.dom.Node @@ -102,4 +105,23 @@ fun BytecodeContext.traverseClassHierarchy(targetClass: MutableClass, callback: this.findClass(targetClass.superclass ?: return)?.mutableClass?.let { traverseClassHierarchy(it, callback) } -} \ No newline at end of file +} + +/** + * Get the [Reference] of an [Instruction] as [T]. + * + * @param T The type of [Reference] to cast to. + * @return The [Reference] as [T] or null + * if the [Instruction] is not a [ReferenceInstruction] or the [Reference] is not of type [T]. + * @see ReferenceInstruction + */ +inline fun Instruction.getReference() = (this as? ReferenceInstruction)?.reference as? T + +/** + * Get the index of the first [Instruction] that matches the predicate. + * + * @param predicate The predicate to match. + * @return The index of the first [Instruction] that matches the predicate. + */ +fun Method.indexOfFirstInstruction(predicate: Instruction.() -> Boolean) = + this.implementation!!.instructions.indexOfFirst(predicate) \ No newline at end of file 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 f397d3184..409785976 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 @@ -4,7 +4,9 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption +import app.revanced.patcher.patch.options.PatchOptionException import org.w3c.dom.Element +import java.io.Closeable @Patch( name = "Change package name", @@ -12,13 +14,11 @@ import org.w3c.dom.Element use = false ) @Suppress("unused") -object ChangePackageNamePatch : ResourcePatch() { - private const val DEFAULT_PACKAGE_NAME_OPTION = "Default" - - private var packageName by stringPatchOption( +object ChangePackageNamePatch : ResourcePatch(), Closeable { + private val packageNameOption = stringPatchOption( key = "packageName", - default = DEFAULT_PACKAGE_NAME_OPTION, - values = mapOf("Default" to DEFAULT_PACKAGE_NAME_OPTION), + default = "Default", + values = mapOf("Default" to "Default"), title = "Package name", description = "The name of the package to rename the app to.", required = true @@ -26,19 +26,37 @@ object ChangePackageNamePatch : ResourcePatch() { it == "Default" || it!!.matches(Regex("^[a-z]\\w*(\\.[a-z]\\w*)+\$")) } + private lateinit var context: ResourceContext + override fun execute(context: ResourceContext) { - fun getOriginalPackageName(context: ResourceContext): String { - context.xmlEditor["AndroidManifest.xml"].use { editor -> - val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element - return manifest.getAttribute("package") - } - } + this.context = context + } - val originalPackageName = getOriginalPackageName(context) - if (packageName == DEFAULT_PACKAGE_NAME_OPTION) packageName = "$originalPackageName.revanced" + /** + * Set the package name to use. + * If this is called multiple times, the first call will set the package name. + * + * @param fallbackPackageName The package name to use if the user has not already specified a package name. + * @return The package name that was set. + * @throws PatchOptionException.ValueValidationException If the package name is invalid. + */ + fun setOrGetFallbackPackageName(fallbackPackageName: String): String { + val packageName = this.packageNameOption.value!! - context["AndroidManifest.xml"].apply { - readText().replace(originalPackageName, packageName!!).let(::writeText) - } + return if (packageName == this.packageNameOption.default) + fallbackPackageName.also { this.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" + + manifest.setAttribute("package", replacementPackageName) } } \ No newline at end of file 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 ce0db09da..a16187681 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 @@ -1,14 +1,19 @@ package app.revanced.patches.all.screenshot.removerestriction +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.util.patch.AbstractTransformInstructionsPatch import app.revanced.util.patch.IMethodCall import app.revanced.util.patch.Instruction35cInfo import app.revanced.util.patch.filterMapInstruction35c +import com.android.tools.smali.dexlib2.Opcode 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 +import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction22c +import com.android.tools.smali.dexlib2.iface.reference.FieldReference @Patch( name = "Remove screenshot restriction", @@ -22,6 +27,11 @@ object RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch, override val returnType: String ): IMethodCall { + AddFlags( + "Landroid/view/Window;", + "addFlags", + arrayOf("I"), + "V", + ), SetFlags( "Landroid/view/Window;", "setFlags", @@ -54,3 +70,37 @@ object RemoveScreenshotRestrictionPatch : AbstractTransformInstructionsPatch>() { + override fun filterMap( + classDef: ClassDef, + method: Method, + instruction: Instruction, + instructionIndex: Int + ): Pair? { + if (instruction.opcode != Opcode.IPUT) { + return null + } + + val instruction22c = instruction as Instruction22c + val fieldReference = instruction22c.reference as FieldReference + + if (fieldReference.definingClass != "Landroid/view/WindowManager\$LayoutParams;" + || fieldReference.name != "flags" + || fieldReference.type != "I") { + return null + } + + return Pair(instruction22c, instructionIndex) + } + + override fun transform(mutableMethod: MutableMethod, entry: Pair) { + val (instruction, index) = entry + val register = instruction.registerA + + mutableMethod.addInstructions( + index, + "and-int/lit16 v$register, v$register, -0x2001" + ) + } +} 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 new file mode 100644 index 000000000..cd7362864 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/all/telephony/sim/spoof/SpoofSimCountryPatch.kt @@ -0,0 +1,111 @@ +package app.revanced.patches.all.telephony.sim.spoof + +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patcher.patch.options.PatchOption +import app.revanced.patcher.patch.options.PatchOption.PatchExtensions.stringPatchOption +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.util.patch.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 +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.reference.MethodReference +import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference +import com.android.tools.smali.dexlib2.util.MethodUtil +import java.util.* + + +@Patch( + name = "Spoof SIM country", + description = "Spoofs country information returned by the SIM card provider.", + use = false, +) +@Suppress("unused") +object SpoofSimCountryPatch : AbstractTransformInstructionsPatch>() { + private val isoValidator: PatchOption.(String?) -> Boolean = + { it: String? -> it?.uppercase() in Locale.getISOCountries() || it == null } + + private val networkCountryIso by stringPatchOption( + "networkCountryIso", + null, + null, + "Network ISO Country Code", + "ISO-3166-1 alpha-2 country code equivalent of the MCC (Mobile Country Code) " + + "of the current registered operator or the cell nearby.", + validator = isoValidator + ) + + private val simCountryIso by stringPatchOption( + "simCountryIso", + null, + null, + "Sim ISO Country Code", + "ISO-3166-1 alpha-2 country code equivalent for the SIM provider's country code.", + validator = isoValidator + ) + + override fun filterMap( + classDef: ClassDef, + method: Method, + instruction: Instruction, + instructionIndex: Int + ): Pair? { + if (instruction !is ReferenceInstruction) return null + + val reference = instruction.reference as? MethodReference ?: return null + + val match = MethodCall.entries.firstOrNull { search -> + MethodUtil.methodSignaturesMatch(reference, search.reference) + } ?: return null + + val iso = when (match) { + MethodCall.NetworkCountryIso -> networkCountryIso + MethodCall.SimCountryIso -> simCountryIso + }?.lowercase() + + return iso?.let { instructionIndex to it } + } + + override fun transform( + mutableMethod: MutableMethod, + entry: Pair + ) = transformMethodCall(entry, mutableMethod) + + private fun transformMethodCall( + entry: Pair, + mutableMethod: MutableMethod + ) { + val (instructionIndex, methodCallValue) = entry + + val register = mutableMethod.getInstruction(instructionIndex + 1).registerA + + mutableMethod.replaceInstruction( + instructionIndex + 1, + "const-string v$register, \"$methodCallValue\"" + ) + } + + private enum class MethodCall( + val reference: MethodReference + ) { + NetworkCountryIso( + ImmutableMethodReference( + "Landroid/telephony/TelephonyManager;", + "getNetworkCountryIso", + emptyList(), + "Ljava/lang/String;" + ) + ), + SimCountryIso( + ImmutableMethodReference( + "Landroid/telephony/TelephonyManager;", + "getSimCountryIso", + emptyList(), + "Ljava/lang/String;" + ) + ) + } +} diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/story/HideStoryAdsPatch.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/story/HideStoryAdsPatch.kt new file mode 100644 index 000000000..68aa84579 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/story/HideStoryAdsPatch.kt @@ -0,0 +1,26 @@ +package app.revanced.patches.facebook.ads.story + +import app.revanced.extensions.exception +import app.revanced.patcher.data.BytecodeContext +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.facebook.ads.story.fingerprints.AdsInsertionFingerprint +import app.revanced.patches.facebook.ads.story.fingerprints.FetchMoreAdsFingerprint + +@Patch( + name = "Hide story ads", + description = "Hides the ads in the Facebook app stories.", + compatiblePackages = [CompatiblePackage("com.facebook.katana")] +) +@Suppress("unused") +object HideStoryAdsPatch : BytecodePatch( + setOf(FetchMoreAdsFingerprint, AdsInsertionFingerprint) +) { + override fun execute(context: BytecodeContext) = + setOf(FetchMoreAdsFingerprint, AdsInsertionFingerprint).forEach { fingerprint -> + fingerprint.result?.mutableMethod?.replaceInstruction(0, "return-void") + ?: throw fingerprint.exception + } +} diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/AdsInsertionFingerprint.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/AdsInsertionFingerprint.kt new file mode 100644 index 000000000..04ffce236 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/AdsInsertionFingerprint.kt @@ -0,0 +1,3 @@ +package app.revanced.patches.facebook.ads.story.fingerprints + +object AdsInsertionFingerprint : FieldMethodFingerprint(fieldValue = "AdBucketDataSourceUtil\$attemptAdsInsertion\$1") \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/FetchMoreAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/FetchMoreAdsFingerprint.kt new file mode 100644 index 000000000..d02c8cc92 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/FetchMoreAdsFingerprint.kt @@ -0,0 +1,3 @@ +package app.revanced.patches.facebook.ads.story.fingerprints + +object FetchMoreAdsFingerprint : FieldMethodFingerprint(fieldValue = "AdBucketDataSourceUtil\$attemptFetchMoreAds\$1") diff --git a/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/FieldMethodFingerprint.kt b/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/FieldMethodFingerprint.kt new file mode 100644 index 000000000..52d6419be --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/facebook/ads/story/fingerprints/FieldMethodFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.facebook.ads.story.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue + +abstract class FieldMethodFingerprint(fieldValue: String) : MethodFingerprint( + returnType = "V", + parameters = listOf(), + customFingerprint = { methodDef, classDef -> + methodDef.name == "run" && classDef.fields.any any@{ field -> + if (field.name != "__redex_internal_original_name") return@any false + (field.initialValue as? StringEncodedValue)?.value == fieldValue + } + } +) diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGBytecodePatch.kt index c1adb1e15..192711a14 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGBytecodePatch.kt @@ -4,18 +4,25 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch import app.revanced.patches.music.misc.microg.fingerprints.* import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants import app.revanced.util.microg.MicroGBytecodeHelper @Patch( name = "Vanced MicroG support", description = "Allows YouTube Music to run without root and under a different package name.", - dependencies = [MicroGResourcePatch::class], - compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")] + dependencies = [ + ChangePackageNamePatch::class, + MicroGResourcePatch::class, + ], + compatiblePackages = [ + CompatiblePackage( + "com.google.android.apps.youtube.music" + ) + ] ) @Suppress("unused") object MicroGBytecodePatch : BytecodePatch( @@ -35,25 +42,29 @@ object MicroGBytecodePatch : BytecodePatch( // - "com.google.android.gms.phenotype.PACKAGE_NAME", // - "com.google.android.gms.phenotype.UPDATE", // - "com.google.android.gms.phenotype", - override fun execute(context: BytecodeContext) = MicroGBytecodeHelper.patchBytecode( - context, - arrayOf( - MicroGBytecodeHelper.packageNameTransform( - Constants.PACKAGE_NAME, - Constants.REVANCED_PACKAGE_NAME + override fun execute(context: BytecodeContext) { + val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(REVANCED_MUSIC_PACKAGE_NAME) + + MicroGBytecodeHelper.patchBytecode( + context, + arrayOf( + MicroGBytecodeHelper.packageNameTransform( + MUSIC_PACKAGE_NAME, + packageName + ) + ), + MicroGBytecodeHelper.PrimeMethodTransformationData( + PrimeFingerprint, + MUSIC_PACKAGE_NAME, + packageName + ), + listOf( + ServiceCheckFingerprint, + GooglePlayUtilityFingerprint, + CastDynamiteModuleFingerprint, + CastDynamiteModuleV2Fingerprint, + CastContextFetchFingerprint ) - ), - MicroGBytecodeHelper.PrimeMethodTransformationData( - PrimeFingerprint, - MUSIC_PACKAGE_NAME, - REVANCED_MUSIC_PACKAGE_NAME - ), - listOf( - ServiceCheckFingerprint, - GooglePlayUtilityFingerprint, - CastDynamiteModuleFingerprint, - CastDynamiteModuleV2Fingerprint, - CastContextFetchFingerprint ) - ) + } } diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGResourcePatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGResourcePatch.kt index eb8daf5ae..950fba8d7 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/MicroGResourcePatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.music.misc.microg 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.packagename.ChangePackageNamePatch import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME @@ -14,15 +15,18 @@ import app.revanced.util.microg.MicroGResourceHelper @Patch( description = "Resource patch to allow YouTube Music ReVanced to run without root " + - "and under a different package name." + "and under a different package name.", + dependencies = [ChangePackageNamePatch::class] ) object MicroGResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { + val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(REVANCED_MUSIC_PACKAGE_NAME) + // update manifest MicroGResourceHelper.patchManifest( context, MUSIC_PACKAGE_NAME, - REVANCED_MUSIC_PACKAGE_NAME, + packageName, REVANCED_MUSIC_APP_NAME ) diff --git a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt index 8fcdf88ed..4be7e77c6 100644 --- a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt +++ b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/UnlockProPatch.kt @@ -10,7 +10,7 @@ import app.revanced.patches.nyx.misc.pro.fingerprints.CheckProFingerprint @Patch( name = "Unlock pro", - compatiblePackages = [CompatiblePackage("com.awedea.nyx")] + compatiblePackages = [CompatiblePackage("com.awedea.nyx", ["2.2.7"])] ) @Suppress("unused") object UnlockProPatch : BytecodePatch(setOf(CheckProFingerprint)) { 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 index 1c38980b6..c1148841c 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt @@ -32,21 +32,29 @@ abstract class AbstractPreferenceScreen( preferences: MutableList = mutableListOf(), val categories: MutableList = mutableListOf() ) : BasePreferenceCollection(key, title, preferences) { - override fun transform(): PreferenceScreen { - return PreferenceScreen( - key, - StringResource("${key}_title", title), - preferences.sortedBy { it.title.value.removePunctuation().lowercase() } + - categories.sortedBy { it.title.removePunctuation().lowercase() }.map { it.transform() }, - summary?.let { summary -> - StringResource("${key}_summary", summary) - } - ) - } + 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)) + if (!this@AbstractPreferenceScreen.root.contains(this)) this@AbstractPreferenceScreen.root.add(this) } @@ -59,7 +67,7 @@ abstract class AbstractPreferenceScreen( key: String, title: String, preferences: MutableList = mutableListOf() - ): BasePreferenceCollection(key, title, preferences) { + ) : BasePreferenceCollection(key, title, preferences) { override fun transform(): PreferenceCategory { return PreferenceCategory( key, @@ -72,7 +80,7 @@ abstract class AbstractPreferenceScreen( ensureScreenInserted() // Add to categories if not yet done - if(!this@Screen.categories.contains(this)) + if (!this@Screen.categories.contains(this)) this@Screen.categories.add(this) this.preferences.addAll(preferences) diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/UnlockPaidWidgetsPatch.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/UnlockPaidWidgetsPatch.kt deleted file mode 100644 index 9b11969b4..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/UnlockPaidWidgetsPatch.kt +++ /dev/null @@ -1,52 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock - -import app.revanced.extensions.exception -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotation.CompatiblePackage -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.twelvewidgets.unlock.fingerprints.* - -@Patch( - name = "Unlock paid widgets", - description = "Unlocks paid widgets of the app", - compatiblePackages = [CompatiblePackage("com.dci.dev.androidtwelvewidgets")] -) -@Suppress("unused") -object UnlockPaidWidgetsPatch : BytecodePatch( - setOf( - AgendaDaysWidgetUnlockFingerprint, - CalendarBigWidgetUnlockFingerprint, - CalendarWideDayEventsWidgetUnlockFingerprint, - CalendarWideTimelineWidgetUnlockFingerprint, - ScreentimeSmallWidgetUnlockFingerprint, - WeatherWidgetUnlockFingerprint - ) -) { - override fun execute(context: BytecodeContext) { - listOf( - AgendaDaysWidgetUnlockFingerprint, - CalendarBigWidgetUnlockFingerprint, - CalendarWideDayEventsWidgetUnlockFingerprint, - CalendarWideTimelineWidgetUnlockFingerprint, - ScreentimeSmallWidgetUnlockFingerprint, - WeatherWidgetUnlockFingerprint - ).map { fingerprint -> - fingerprint.result?.mutableMethod ?: throw fingerprint.exception - }.forEach { method -> - method.apply { - removeInstructions(4, 3) - addInstructions( - implementation?.instructions?.size!!, - """ - const/4 v1, 0x0 - invoke-virtual {v0, v1}, Landroid/view/View;->setVisibility(I)V - return-object v0 - """ - ) - } - } - } -} diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/AgendaDaysWidgetUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/AgendaDaysWidgetUnlockFingerprint.kt deleted file mode 100644 index d3330bd5c..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/AgendaDaysWidgetUnlockFingerprint.kt +++ /dev/null @@ -1,3 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -object AgendaDaysWidgetUnlockFingerprint : MethodUnlockFingerprint("AgendaDaysWidgetConfigureActivity") diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarBigWidgetUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarBigWidgetUnlockFingerprint.kt deleted file mode 100644 index ed930a26c..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarBigWidgetUnlockFingerprint.kt +++ /dev/null @@ -1,3 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -object CalendarBigWidgetUnlockFingerprint : MethodUnlockFingerprint("CalendarBigWidgetConfigureActivity") diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarWideDayEventsWidgetUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarWideDayEventsWidgetUnlockFingerprint.kt deleted file mode 100644 index adf3b82a8..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarWideDayEventsWidgetUnlockFingerprint.kt +++ /dev/null @@ -1,4 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -object CalendarWideDayEventsWidgetUnlockFingerprint : - MethodUnlockFingerprint("CalendarWideDayEventsWidgetConfigureActivity") diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarWideTimelineWidgetUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarWideTimelineWidgetUnlockFingerprint.kt deleted file mode 100644 index c4f79eff5..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/CalendarWideTimelineWidgetUnlockFingerprint.kt +++ /dev/null @@ -1,4 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -object CalendarWideTimelineWidgetUnlockFingerprint : - MethodUnlockFingerprint("CalendarWideTimelineWidgetConfigureActivity") diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/MethodUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/MethodUnlockFingerprint.kt deleted file mode 100644 index aa99109b3..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/MethodUnlockFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint - -abstract class MethodUnlockFingerprint(private val className: String) : MethodFingerprint( - "L", - strings = listOf("binding.addButton"), - customFingerprint = { methodDef, _ -> - methodDef.definingClass.endsWith("/$className;") - } -) - diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/ScreentimeSmallWidgetUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/ScreentimeSmallWidgetUnlockFingerprint.kt deleted file mode 100644 index 7cfdc0246..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/ScreentimeSmallWidgetUnlockFingerprint.kt +++ /dev/null @@ -1,3 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -object ScreentimeSmallWidgetUnlockFingerprint : MethodUnlockFingerprint("ScreentimeSmallWidgetConfigureActivity") diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/WeatherWidgetUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/WeatherWidgetUnlockFingerprint.kt deleted file mode 100644 index 17bd9e951..000000000 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/WeatherWidgetUnlockFingerprint.kt +++ /dev/null @@ -1,3 +0,0 @@ -package app.revanced.patches.twelvewidgets.unlock.fingerprints - -object WeatherWidgetUnlockFingerprint : MethodUnlockFingerprint("WeatherWidgetConfigureActivity") 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 ae47f07d1..a360deaa5 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 @@ -17,7 +17,7 @@ import app.revanced.patches.twitch.misc.settings.SettingsPatch name = "Block audio ads", description = "Blocks audio ads in streams and VODs.", dependencies = [IntegrationsPatch::class, SettingsPatch::class], - compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0"])], + compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "17.0.0", "17.1.0"])], ) @Suppress("unused") object AudioAdsPatch : BytecodePatch( 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 3decfdb4a..4e25be641 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 @@ -18,7 +18,7 @@ import app.revanced.patches.twitch.misc.settings.SettingsPatch name = "Block embedded ads", description = "Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.", dependencies = [VideoAdsPatch::class, IntegrationsPatch::class, SettingsPatch::class], - compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0"])] + compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "17.0.0", "17.1.0"])] ) @Suppress("unused") object EmbeddedAdsPatch : BytecodePatch( 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 b6fffe067..08dd15697 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 @@ -21,7 +21,7 @@ import app.revanced.patches.twitch.misc.settings.SettingsPatch name = "Block video ads", description = "Blocks video ads in streams and VODs.", dependencies = [IntegrationsPatch::class, SettingsPatch::class], - compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0"])] + compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "17.0.0", "17.1.0"])] ) object VideoAdsPatch : AbstractAdPatch( "Lapp/revanced/twitch/patches/VideoAdsPatch;->shouldBlockVideoAds()Z", 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 3e41e8650..615533297 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 @@ -22,7 +22,7 @@ import app.revanced.patches.twitch.misc.settings.SettingsPatch name = "Show deleted messages", description = "Shows deleted chat messages behind a clickable spoiler.", dependencies = [IntegrationsPatch::class, SettingsPatch::class], - compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0"])] + compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "17.0.0", "17.1.0"])] ) @Suppress("unused") object ShowDeletedMessagesPatch : BytecodePatch( 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 8a23e047d..154df30db 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 @@ -17,7 +17,7 @@ import app.revanced.patches.twitch.misc.settings.SettingsPatch name = "Auto claim channel points", description = "Automatically claim Channel Points.", dependencies = [SettingsPatch::class], - compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0"])] + compatiblePackages = [CompatiblePackage("tv.twitch.android.app", ["15.4.1", "16.1.0", "17.0.0", "17.1.0"])] ) @Suppress("unused") object AutoClaimChannelPointPatch : BytecodePatch( 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 a76288abe..bfec38ad4 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 @@ -33,7 +33,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 1e7a75e8d..8922a1aea 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 @@ -27,7 +27,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 5ff58b6a9..1a545139e 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 @@ -31,7 +31,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 ee8a4b240..ef06b29bf 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 @@ -26,7 +26,10 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 c5310675d..2f9b49167 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 @@ -26,7 +26,10 @@ import app.revanced.patches.youtube.video.information.VideoInformationPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ), ] 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 54465b2aa..ccb73953c 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 @@ -24,7 +24,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction [ "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 89bee3bde..1bf7c17c8 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 @@ -27,14 +27,9 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference CompatiblePackage( "com.google.android.youtube", [ - "18.16.37", - "18.19.35", - "18.20.39", - "18.23.35", - "18.29.38", - "18.32.39", - "18.37.36", - "18.38.44" + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] @@ -64,8 +59,8 @@ object EnableSeekbarTappingPatch : BytecodePatch( .reference as MethodReference buildMap { - put("O", getReference(patternScanResult.endIndex)) put("N", getReference(patternScanResult.startIndex)) + put("O", getReference(patternScanResult.endIndex)) } } 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 new file mode 100644 index 000000000..851ab34ec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/EnableSlideToSeekPatch.kt @@ -0,0 +1,84 @@ +package app.revanced.patches.youtube.interaction.seekbar + +import app.revanced.extensions.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.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 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.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class], + compatiblePackages = [ + CompatiblePackage( + "com.google.android.youtube", + [ + "18.43.45", + "18.44.41", + "18.45.41" + ] + ) + ] +) +@Suppress("unused") +object EnableSlideToSeekPatch : BytecodePatch( + setOf( + SlideToSeekFingerprint, + DoubleSpeedSeekNoticeFingerprint + ) +) { + const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/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" + ), + ) + ) + + arrayOf( + // Restore the behaviour to slide to seek. + SlideToSeekFingerprint, + // Disable the double speed seek notice. + DoubleSpeedSeekNoticeFingerprint + ).map { + it.result ?: throw it.exception + }.forEach { + val insertIndex = it.scanResult.patternScanResult!!.endIndex + 1 + + it.mutableMethod.apply { + val isEnabledRegister = getInstruction(insertIndex).registerA + + addInstructions( + insertIndex, + """ + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isSlideToSeekDisabled()Z + move-result v$isEnabledRegister + """ + ) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DoubleSpeedSeekNoticeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DoubleSpeedSeekNoticeFingerprint.kt new file mode 100644 index 000000000..c02ca6b45 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/DoubleSpeedSeekNoticeFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.youtube.interaction.seekbar.fingerprints + +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.Opcode + +object DoubleSpeedSeekNoticeFingerprint : LiteralValueFingerprint( + returnType = "Z", + parameters = emptyList(), + opcodes = listOf(Opcode.MOVE_RESULT), + literalSupplier = { 45411330 } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/IsSwipingUpFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/IsSwipingUpFingerprint.kt index 72b7bc43c..0a750f715 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/IsSwipingUpFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/IsSwipingUpFingerprint.kt @@ -4,6 +4,10 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.Opcode object IsSwipingUpFingerprint : MethodFingerprint( + returnType = "Z", parameters = listOf("Landroid/view/MotionEvent;", "J"), - opcodes = listOf(Opcode.SGET_OBJECT) + opcodes = listOf( + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT + ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/OnTouchEventHandlerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/OnTouchEventHandlerFingerprint.kt index f4607b0d5..2c355e086 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/OnTouchEventHandlerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/OnTouchEventHandlerFingerprint.kt @@ -1,8 +1,8 @@ package app.revanced.patches.youtube.interaction.seekbar.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -12,7 +12,7 @@ object OnTouchEventHandlerFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.PUBLIC, parameters = listOf("L"), opcodes = listOf( - Opcode.INVOKE_VIRTUAL, // oMethodReference + Opcode.INVOKE_VIRTUAL, // nMethodReference Opcode.RETURN, Opcode.IGET_OBJECT, Opcode.IGET_BOOLEAN, @@ -23,10 +23,9 @@ object OnTouchEventHandlerFingerprint : MethodFingerprint( Opcode.INT_TO_FLOAT, Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.RETURN, + Opcode.IF_EQZ, Opcode.INVOKE_VIRTUAL, - Opcode.INVOKE_VIRTUAL, // pMethodReference + Opcode.INVOKE_VIRTUAL, // oMethodReference ), customFingerprint = { methodDef, _ -> methodDef.name == "onTouchEvent" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt new file mode 100644 index 000000000..76a97d08a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SlideToSeekFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.youtube.interaction.seekbar.fingerprints + +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.Opcode + +object SlideToSeekFingerprint : LiteralValueFingerprint( + returnType = "Z", + parameters = emptyList(), + opcodes = listOf(Opcode.MOVE_RESULT), + literalSupplier = { 45411329 } +) \ No newline at end of file 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 eeff69b00..640e9fc5f 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 @@ -33,7 +33,10 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethod "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 8a6525a7d..e63ebff37 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 @@ -31,7 +31,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ], 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 633a31893..dca362df9 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 @@ -29,7 +29,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 2ef5e0316..f1d1e4b0f 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 @@ -39,7 +39,10 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 a8598a9ac..7b16c6063 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 @@ -30,7 +30,10 @@ import com.android.tools.smali.dexlib2.Opcode "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 736b45755..3dd68a9a1 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 @@ -15,7 +15,6 @@ import app.revanced.patches.youtube.layout.buttons.navigation.utils.InjectionUti 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 com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( @@ -37,7 +36,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] @@ -98,6 +100,10 @@ object NavigationButtonsPatch : BytecodePatch( ), ), ), + StringResource( + "revanced_navigation_buttons_preference_screen_summary", + "Hide or change buttons in the navigation bar" + ) ) ) @@ -177,13 +183,7 @@ object NavigationButtonsPatch : BytecodePatch( } PivotBarCreateButtonViewFingerprint.result!!.apply { - val insertIndex = mutableMethod.implementation!!.instructions.let { - val scanStart = scanResult.patternScanResult!!.endIndex - - scanStart + it.subList(scanStart, it.size - 1).indexOfFirst { instruction -> - instruction.opcode == Opcode.INVOKE_STATIC - } - } + val insertIndex = scanResult.patternScanResult!!.endIndex /* * Inject hooks diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarCreateButtonViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarCreateButtonViewFingerprint.kt index 71eb4ae28..2b209b94f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarCreateButtonViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarCreateButtonViewFingerprint.kt @@ -5,7 +5,9 @@ import com.android.tools.smali.dexlib2.Opcode object PivotBarCreateButtonViewFingerprint : MethodFingerprint( opcodes = listOf( - Opcode.MOVE_OBJECT, - Opcode.INVOKE_DIRECT_RANGE, // unique instruction anchor + Opcode.INVOKE_DIRECT_RANGE, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/HidePlayerButtonsPatch.kt index a299c211d..68ae20e40 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 @@ -34,7 +34,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction3rc "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 a6cb2db76..ed47b23fe 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 @@ -29,7 +29,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 e938dc70e..2f48a34c2 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 @@ -29,7 +29,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 a783a30ca..b80fdccb8 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 @@ -28,7 +28,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 a9d4996b5..1c3d196cb 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 @@ -29,7 +29,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 67cb14541..417e75105 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 @@ -32,7 +32,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction21c "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 78a871753..ca4be498b 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 @@ -29,7 +29,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 3ad8a7ec3..ea14ca3bd 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 @@ -25,7 +25,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 2c83e8a05..f68ed1871 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 @@ -20,7 +20,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 a71aed1eb..00f7e9636 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 @@ -11,10 +11,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.smali.ExternalLabel -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.shared.settings.preference.impl.* 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 @@ -23,6 +20,7 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch.PreferenceScreen import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @Patch( name = "Hide layout components", @@ -36,7 +34,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction "com.google.android.youtube", [ "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] @@ -45,8 +46,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction object HideLayoutComponentsPatch : BytecodePatch( setOf(ParseElementFromBufferFingerprint, PlayerOverlayFingerprint) ) { - private const val FILTER_CLASS_DESCRIPTOR = + private const val LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/LayoutComponentsFilter;" + private const val DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME = + "Lapp/revanced/integrations/patches/components/DescriptionComponentsFilter;" override fun execute(context: BytecodeContext) { PreferenceScreen.LAYOUT.addPreferences( @@ -284,7 +287,95 @@ object HideLayoutComponentsPatch : BytecodePatch( StringResource("revanced_hide_chips_shelf_on", "Chips shelf is hidden"), StringResource("revanced_hide_chips_shelf_off", "Chips shelf is shown") ), - app.revanced.patches.shared.settings.preference.impl.PreferenceScreen( + 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" + ) + ), + PreferenceScreen( "revanced_custom_filter_preference_screen", StringResource("revanced_custom_filter_preference_screen_title", "Custom filter"), listOf( @@ -313,11 +404,16 @@ object HideLayoutComponentsPatch : BytecodePatch( ), inputType = InputType.TEXT_MULTI_LINE ) + ), + StringResource( + "revanced_custom_filter_preference_screen_summary", + "Hide components using custom filters" ) ) ) - LithoFilterPatch.addFilter(FILTER_CLASS_DESCRIPTOR) + LithoFilterPatch.addFilter(LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR) + LithoFilterPatch.addFilter(DESCRIPTION_COMPONENTS_FILTER_CLASS_NAME) // region Mix playlists @@ -327,12 +423,15 @@ object HideLayoutComponentsPatch : BytecodePatch( result.mutableMethod.apply { val consumeByteBufferIndex = result.scanResult.patternScanResult!!.startIndex - val byteBufferRegister = getInstruction(consumeByteBufferIndex).registerD + val conversionContextRegister = + getInstruction(consumeByteBufferIndex - 2).registerA + val byteBufferRegister = + getInstruction(consumeByteBufferIndex).registerD addInstructionsWithLabels( - result.scanResult.patternScanResult!!.startIndex, + consumeByteBufferIndex, """ - invoke-static {v$byteBufferRegister}, $FILTER_CLASS_DESCRIPTOR->filterMixPlaylists([B)Z + 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 """, @@ -355,7 +454,7 @@ object HideLayoutComponentsPatch : BytecodePatch( addInstructions( index, """ - invoke-static {}, $FILTER_CLASS_DESCRIPTOR->showWatermark()Z + 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 c653fa6aa..e4e8fa5d1 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 @@ -36,7 +36,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 0e7ac6276..3cf1a780a 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 @@ -25,7 +25,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 6d0265078..de764d7cf 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 @@ -25,7 +25,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 a6085a4fc..c618eb35a 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 @@ -28,7 +28,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41", ]) ] ) 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 f435e5786..d0fcdb8e5 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 @@ -33,7 +33,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 372294c1c..8d9d940b7 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 @@ -37,7 +37,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 5c338cfe1..8636cd3a0 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 @@ -19,7 +19,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 58c8bbad0..8fddc2252 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 @@ -26,7 +26,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/fingerprints/TimeCounterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/fingerprints/TimeCounterFingerprint.kt index 164698dcb..4cf61b209 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/fingerprints/TimeCounterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/fingerprints/TimeCounterFingerprint.kt @@ -1,24 +1,25 @@ package app.revanced.patches.youtube.layout.hide.time.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @FuzzyPatternScanMethod(1) object TimeCounterFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( - Opcode.IGET_OBJECT, + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + emptyList(), + listOf( + Opcode.SUB_LONG_2ADDR, Opcode.IGET_WIDE, - Opcode.CONST_WIDE_16, - Opcode.CMP_LONG, - Opcode.IF_LEZ, + Opcode.SUB_LONG_2ADDR, Opcode.IGET_OBJECT, - Opcode.IF_EQZ, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.GOTO, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IGET_WIDE, + Opcode.IGET_WIDE, + Opcode.SUB_LONG_2ADDR ) ) \ No newline at end of file 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 c52ec616d..932c991ba 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 @@ -26,7 +26,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 80202da0b..e83b4eb34 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 @@ -20,7 +20,10 @@ import org.w3c.dom.Element "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ], 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 311c958f2..e94b69485 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,6 +1,8 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike import app.revanced.extensions.exception +import app.revanced.extensions.getReference +import app.revanced.extensions.indexOfFirstInstruction import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions @@ -9,6 +11,7 @@ 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.* @@ -20,6 +23,7 @@ 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.MethodReference @Patch( name = "Return YouTube Dislike", @@ -32,7 +36,13 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction PlayerTypeHookPatch::class, ], compatiblePackages = [ - CompatiblePackage("com.google.android.youtube", ["18.37.36", "18.38.44"]) + CompatiblePackage( + "com.google.android.youtube", [ + "18.43.45", + "18.44.41", + "18.45.41" + ] + ) ] ) @Suppress("unused") @@ -44,6 +54,8 @@ object ReturnYouTubeDislikePatch : BytecodePatch( LikeFingerprint, DislikeFingerprint, RemoveLikeFingerprint, + RollingNumberSetterFingerprint, + RollingNumberTextViewFingerprint ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = @@ -138,7 +150,77 @@ object ReturnYouTubeDislikePatch : BytecodePatch( // endregion - // region Hook for non litho Short videos. + // region Hook rolling numbers. + + RollingNumberSetterFingerprint.result?.let { + val dislikesIndex = it.scanResult.patternScanResult!!.endIndex + + it.mutableMethod.apply { + val insertIndex = 1 + + val charSequenceInstanceRegister = + getInstruction(0).registerA + val charSequenceFieldReference = + getInstruction(dislikesIndex).reference.toString() + + val registerCount = implementation!!.registerCount + + // This register is being overwritten, so it is free to use. + val freeRegister = registerCount - 1 + val conversionContextRegister = registerCount - parameters.size + 1 + + addInstructions( + insertIndex, + """ + iget-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference + invoke-static {v$conversionContextRegister, v$freeRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->onRollingNumberLoaded(Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/String; + move-result-object v$freeRegister + iput-object v$freeRegister, v$charSequenceInstanceRegister, $charSequenceFieldReference + """ + ) + } + } ?: throw RollingNumberSetterFingerprint.exception + + // The rolling number Span is missing styling since it's initially set as a String. + // Modify the UI text view and use the styled like/dislike Span. + RollingNumberTextViewFingerprint.result?.let { + // Initial TextView is set in this method. + val initiallyCreatedTextViewMethod = it.mutableMethod + + // Videos less than 24 hours after uploaded, like counts will be updated in real time. + // Whenever like counts are updated, TextView is set in this method. + val realTimeUpdateTextViewMethod = it.mutableClass.methods.find { method -> + method.parameterTypes.first() == "Landroid/graphics/Bitmap;" + } ?: throw PatchException("Failed to find realTimeUpdateTextViewMethod") + + arrayOf( + initiallyCreatedTextViewMethod, + realTimeUpdateTextViewMethod + ).forEach { insertMethod -> + insertMethod.apply { + val setTextIndex = indexOfFirstInstruction { + getReference()?.name == "setText" + } + + val textViewRegister = + getInstruction(setTextIndex).registerC + val textSpanRegister = + getInstruction(setTextIndex).registerD + + addInstructions( + setTextIndex, + """ + invoke-static {v$textViewRegister, v$textSpanRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->updateRollingNumber(Landroid/widget/TextView;Ljava/lang/CharSequence;)Ljava/lang/CharSequence; + move-result-object v$textSpanRegister + """ + ) + } + } + } ?: throw RollingNumberTextViewFingerprint.exception + + // endregion + + // region Hook for non-litho Short videos. ShortsTextViewFingerprint.result?.let { it.mutableMethod.apply { @@ -167,7 +249,7 @@ object ReturnYouTubeDislikePatch : BytecodePatch( move-result v0 if-eqz v0, :ryd_disabled return-void - + :is_like :ryd_disabled nop diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt new file mode 100644 index 000000000..cf0857c61 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberSetterFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +object RollingNumberSetterFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.INVOKE_DIRECT, + Opcode.IGET_OBJECT + ), + strings = listOf("RollingNumberType required properties missing! Need updateCount, fontName, color and fontSize.") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt new file mode 100644 index 000000000..9c79cf4f5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RollingNumberTextViewFingerprint.kt @@ -0,0 +1,23 @@ +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 + +object RollingNumberTextViewFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L", "F", "F"), + opcodes = listOf( + Opcode.IPUT, + null, // invoke-direct or invoke-virtual + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ), + customFingerprint = custom@{ _, classDef -> + classDef.superclass == "Landroid/support/v7/widget/AppCompatTextView;" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt index a86701918..5f8521dd6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt @@ -12,7 +12,7 @@ object ShortsTextViewFingerprint : MethodFingerprint( opcodes = listOf( Opcode.INVOKE_SUPER, // first instruction of method Opcode.IF_NEZ, - Opcode.RETURN_VOID, + null, Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST, 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 index e69128012..41f20e8b3 100644 --- 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 @@ -18,7 +18,7 @@ object TextComponentAtomicReferenceFingerprint : MethodFingerprint( 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, 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 index 75a9f5989..5c175b726 100644 --- 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 @@ -21,6 +21,7 @@ object TextComponentContextFingerprint : MethodFingerprint( 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/searchbar/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/WideSearchbarPatch.kt index 5a123233f..aca9c32f9 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 @@ -29,7 +29,9 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.45.41" ] ) ] @@ -69,7 +71,7 @@ object WideSearchbarPatch : BytecodePatch( * @param fromFingerprint The fingerprint to walk the method on. * @return The [MutableMethod] which was walked on. */ - fun BytecodeContext.walkMutable(index: Int, fromFingerprint: MethodFingerprint) = + private fun BytecodeContext.walkMutable(index: Int, fromFingerprint: MethodFingerprint) = fromFingerprint.result?.let { toMethodWalker(it.method).nextMethod(index, true).getMethod() as MutableMethod } ?: throw fromFingerprint.exception @@ -78,7 +80,7 @@ object WideSearchbarPatch : BytecodePatch( /** * Injects instructions required for certain methods. */ - fun MutableMethod.injectSearchBarHook() { + private fun MutableMethod.injectSearchBarHook() { addInstructions( implementation!!.instructions.size - 1, """ diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/EnableOldSeekbarThumbnailsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt similarity index 63% rename from src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/EnableOldSeekbarThumbnailsPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt index 5e8562ff2..50b3d7a7f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/EnableOldSeekbarThumbnailsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/RestoreOldSeekbarThumbnailsPatch.kt @@ -9,56 +9,59 @@ 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.youtube.layout.seekbar.fingerprints.EnableNewSeekbarThumbnailsFingerprint +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 @Patch( - name = "Enable old seekbar thumbnails", - description = "Enables the old seekbar thumbnails that appear above the seekbar instead of in fullscreen.", + name = "Restore old seekbar thumbnails", + description = "Restores the old seekbar thumbnails that appear above the seekbar instead of fullscreen thumbnails.", dependencies = [IntegrationsPatch::class, SettingsPatch::class], compatiblePackages = [ CompatiblePackage( "com.google.android.youtube", [ "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] ) @Suppress("unused") -object EnableOldSeekbarThumbnailsPatch : BytecodePatch( - setOf(EnableNewSeekbarThumbnailsFingerprint) +object RestoreOldSeekbarThumbnailsPatch : BytecodePatch( + setOf(FullscreenSeekbarThumbnailsFingerprint) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/EnableOldSeekbarThumbnailsPatch;" + "Lapp/revanced/integrations/patches/RestoreOldSeekbarThumbnailsPatch;" override fun execute(context: BytecodeContext) { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( SwitchPreference( - "revanced_enable_old_seekbar_thumbnails", + "revanced_restore_old_seekbar_thumbnails", StringResource( - "revanced_enable_old_seekbar_thumbnails_title", - "Enable old seekbar thumbnails" + "revanced_restore_old_seekbar_thumbnails_title", + "Restore old seekbar thumbnails" ), StringResource( - "revanced_enable_old_seekbar_thumbnails_summary_on", + "revanced_restore_old_seekbar_thumbnails_summary_on", "Seekbar thumbnails will appear above the seekbar" ), StringResource( - "revanced_enable_old_seekbar_thumbnails_summary_off", + "revanced_restore_old_seekbar_thumbnails_summary_off", "Seekbar thumbnails will appear in fullscreen" ), ) ) - EnableNewSeekbarThumbnailsFingerprint.result?.mutableMethod?.apply { + FullscreenSeekbarThumbnailsFingerprint.result?.mutableMethod?.apply { val moveResultIndex = getInstructions().lastIndex - 1 addInstruction( moveResultIndex, - "invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->enableOldSeekbarThumbnails()Z" + "invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->useFullscreenSeekbarThumbnails()Z" ) - } ?: throw EnableNewSeekbarThumbnailsFingerprint.exception + } ?: throw FullscreenSeekbarThumbnailsFingerprint.exception } } 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 1283fd233..0b7a41fda 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 @@ -22,8 +22,12 @@ object SeekbarPreferencesPatch : ResourcePatch(), Closeable { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( "revanced_seekbar_preference_screen", - StringResource("revanced_seekbar_preference_screen_title", "Seekbar settings"), - seekbarPreferences + StringResource("revanced_seekbar_preference_screen_title", "Seekbar"), + seekbarPreferences, + StringResource( + "revanced_seekbar_preference_screen_summary", + "Settings for the seekbar." + ) ) ) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/EnableNewSeekbarThumbnailsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/FullscreenSeekbarThumbnailsFingerprint.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/EnableNewSeekbarThumbnailsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/FullscreenSeekbarThumbnailsFingerprint.kt index 525f81a07..96610fe04 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/EnableNewSeekbarThumbnailsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/fingerprints/FullscreenSeekbarThumbnailsFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.extensions.or import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.AccessFlags -object EnableNewSeekbarThumbnailsFingerprint : LiteralValueFingerprint( +object FullscreenSeekbarThumbnailsFingerprint : LiteralValueFingerprint( returnType = "Z", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = emptyList(), 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 9e7c88629..971c55fc3 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 @@ -12,7 +12,6 @@ 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.fingerprints.LayoutConstructorFingerprint -import app.revanced.patches.youtube.shared.fingerprints.SeekbarFingerprint import app.revanced.patches.shared.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.shared.mapping.misc.ResourceMappingPatch import app.revanced.patches.youtube.layout.sponsorblock.fingerprints.AppendTimeFingerprint @@ -23,6 +22,7 @@ import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParen import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsBytecodePatch import app.revanced.patches.youtube.misc.playertype.PlayerTypeHookPatch +import app.revanced.patches.youtube.shared.fingerprints.SeekbarFingerprint import app.revanced.patches.youtube.video.information.VideoInformationPatch import app.revanced.patches.youtube.video.videoid.VideoIdPatch import com.android.tools.smali.dexlib2.Opcode @@ -45,7 +45,10 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ], 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 fcbdef357..711afb953 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 @@ -30,7 +30,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableShortsOnStartupPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt similarity index 62% rename from src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableShortsOnStartupPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt index 7b90a378b..aa3f95d07 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableShortsOnStartupPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/DisableResumingShortsOnStartupPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.startupshortsreset +import app.revanced.extensions.exception import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.patch.BytecodePatch @@ -12,8 +13,8 @@ import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( - name = "Disable Shorts on startup", - description = "Disables playing YouTube Shorts when launching YouTube.", + 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], compatiblePackages = [ CompatiblePackage( @@ -25,39 +26,46 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] ) @Suppress("unused") -object DisableShortsOnStartupPatch : BytecodePatch( +object DisableResumingShortsOnStartupPatch : BytecodePatch( setOf(UserWasInShortsFingerprint) ) { + + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/patches/DisableResumingStartupShortsPlayerPatch;" + override fun execute(context: BytecodeContext) { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( SwitchPreference( "revanced_disable_resuming_shorts_player", - StringResource("revanced_disable_resuming_shorts_player_title", "Disable Shorts player at app startup"), - StringResource("revanced_disable_resuming_shorts_player_summary_on", "Shorts player is disabled at app startup"), - StringResource("revanced_disable_resuming_shorts_player_summary_off", "Shorts player is enabled at app startup") + 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") ) ) - val userWasInShortsResult = UserWasInShortsFingerprint.result!! - val userWasInShortsMethod = userWasInShortsResult.mutableMethod - val moveResultIndex = userWasInShortsResult.scanResult.patternScanResult!!.endIndex + UserWasInShortsFingerprint.result?.apply { + val moveResultIndex = scanResult.patternScanResult!!.endIndex - userWasInShortsMethod.addInstructionsWithLabels( - moveResultIndex + 1, - """ - invoke-static { }, Lapp/revanced/integrations/patches/DisableStartupShortsPlayerPatch;->disableStartupShortsPlayer()Z + mutableMethod.addInstructionsWithLabels( + moveResultIndex + 1, + """ + invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z move-result v5 if-eqz v5, :disable_shorts_player return-void :disable_shorts_player nop """ - ) + ) + } ?: throw UserWasInShortsFingerprint.exception } } 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 e8fbb906f..e25a44712 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 @@ -34,7 +34,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ) ) ] 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 c03b29ccc..9ed397d3b 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 @@ -32,7 +32,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "com.google.android.youtube", [ "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] @@ -82,7 +85,7 @@ object ThemeBytecodePatch : BytecodePatch( "Light red" to "#FFFFD6D6" ), title = "Light theme background color", - description = "Can be a hex color or a color resource reference.", + description = "Can be a hex color (#AARRGGBB) or a color resource reference.", ) override fun execute(context: BytecodeContext) { 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 aaeddced4..8bc99eebe 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 @@ -26,7 +26,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 2f7ff15ee..50c4dd4a2 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 @@ -30,7 +30,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 fe93dd149..04ee6f210 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 @@ -21,7 +21,10 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch CompatiblePackage( "com.google.android.youtube", [ - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 3afec9416..22f89ba79 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 @@ -26,7 +26,10 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 0cd3deb8e..1346f746a 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 @@ -18,6 +18,7 @@ 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 com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction @Patch( description = "Spoofs the signature to prevent playback issues.", @@ -26,14 +27,19 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction PlayerTypeHookPatch::class, PlayerResponseMethodHookPatch::class, VideoInformationPatch::class, + SpoofSignatureResourcePatch::class ] ) object SpoofSignaturePatch : BytecodePatch( setOf( - PlayerResponseModelImplFingerprint, - StoryboardThumbnailParentFingerprint, + PlayerResponseModelImplGeneralFingerprint, + PlayerResponseModelImplLiveStreamFingerprint, + PlayerResponseModelImplRecommendedLevel, StoryboardRendererSpecFingerprint, - StoryboardRendererInitFingerprint + StoryboardRendererDecoderSpecFingerprint, + StoryboardRendererDecoderRecommendedLevelFingerprint, + StoryboardThumbnailParentFingerprint, + ScrubbedPreviewLayoutFingerprint, ) ) { private const val INTEGRATIONS_CLASS_DESCRIPTOR = @@ -42,12 +48,12 @@ object SpoofSignaturePatch : BytecodePatch( override fun execute(context: BytecodeContext) { SettingsPatch.PreferenceScreen.MISC.addPreferences( PreferenceScreen( - key = "revanced_spoof_signature_verification", - title = StringResource( + "revanced_spoof_signature_verification", + StringResource( "revanced_spoof_signature_verification_title", "Spoof app signature" ), - preferences = listOf( + listOf( SwitchPreference( "revanced_spoof_signature_verification_enabled", StringResource("revanced_spoof_signature_verification_enabled_title", "Spoof app signature"), @@ -83,7 +89,23 @@ object SpoofSignaturePatch : BytecodePatch( "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" ) ) ) @@ -94,7 +116,8 @@ object SpoofSignaturePatch : BytecodePatch( ) // Force the seekbar time and chapters to always show up. - // This is used only if the storyboard spec fetch fails, or when viewing paid videos. + // This is used if the storyboard spec fetch fails, for viewing paid videos, + // or if storyboard spoofing is turned off. StoryboardThumbnailParentFingerprint.result?.classDef?.let { classDef -> StoryboardThumbnailFingerprint.also { it.resolve( @@ -124,23 +147,74 @@ object SpoofSignaturePatch : BytecodePatch( } ?: throw StoryboardThumbnailFingerprint.exception } - /** - * Hook StoryBoard renderer url - */ - PlayerResponseModelImplFingerprint.result?.let { - it.mutableMethod.apply { - val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex - val getStoryBoardRegister = getInstruction(getStoryBoardIndex).registerA - + // If storyboard spoofing is turned off, then hide the empty seekbar thumbnail view. + ScrubbedPreviewLayoutFingerprint.result?.apply { + val endIndex = scanResult.patternScanResult!!.endIndex + mutableMethod.apply { + val imageViewFieldName = getInstruction(endIndex).reference addInstructions( - getStoryBoardIndex, + implementation!!.instructions.lastIndex, """ - invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$getStoryBoardRegister + iget-object v0, p0, $imageViewFieldName # copy imageview field to a register + invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->seekbarImageViewCreated(Landroid/widget/ImageView;)V """ ) } - } ?: throw PlayerResponseModelImplFingerprint.exception + } ?: throw ScrubbedPreviewLayoutFingerprint.exception + + /** + * Hook StoryBoard renderer url + */ + arrayOf( + PlayerResponseModelImplGeneralFingerprint, + PlayerResponseModelImplLiveStreamFingerprint + ).forEach { fingerprint -> + fingerprint.result?.let { + it.mutableMethod.apply { + val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex + val getStoryBoardRegister = + getInstruction(getStoryBoardIndex).registerA + + addInstructions( + getStoryBoardIndex, + """ + invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$getStoryBoardRegister + """ + ) + } + } ?: throw fingerprint.exception + } + + // Hook recommended seekbar thumbnails quality level. + StoryboardRendererDecoderRecommendedLevelFingerprint.result?.let { + val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex + val originalValueRegister = it.mutableMethod + .getInstruction(moveOriginalRecommendedValueIndex).registerA + + it.mutableMethod.addInstructions( + moveOriginalRecommendedValueIndex + 1, """ + invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I + move-result v$originalValueRegister + """ + ) + } ?: throw StoryboardRendererDecoderRecommendedLevelFingerprint.exception + + // Hook the recommended precise seeking thumbnails quality level. + PlayerResponseModelImplRecommendedLevel.result?.let { + it.mutableMethod.apply { + val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex + val originalValueRegister = + getInstruction(moveOriginalRecommendedValueIndex).registerA + + addInstructions( + moveOriginalRecommendedValueIndex, """ + invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I + move-result v$originalValueRegister + """ + ) + } + } ?: throw PlayerResponseModelImplRecommendedLevel.exception StoryboardRendererSpecFingerprint.result?.let { it.mutableMethod.apply { @@ -158,22 +232,18 @@ object SpoofSignaturePatch : BytecodePatch( } } ?: throw StoryboardRendererSpecFingerprint.exception - // Hook recommended value - StoryboardRendererInitFingerprint.result?.let { - val moveOriginalRecommendedValueIndex = it.scanResult.patternScanResult!!.endIndex + // Hook the seekbar thumbnail decoder and use a NULL spec for live streams. + StoryboardRendererDecoderSpecFingerprint.result?.let { + val storyBoardUrlIndex = it.scanResult.patternScanResult!!.startIndex + 1 + val storyboardUrlRegister = + it.mutableMethod.getInstruction(storyBoardUrlIndex).registerA - val originalValueRegister = it.mutableMethod - .getInstruction(moveOriginalRecommendedValueIndex).registerA - - it.mutableMethod.apply { - addInstructions( - moveOriginalRecommendedValueIndex + 1, - """ - invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I - move-result v$originalValueRegister - """ - ) - } - } ?: throw StoryboardRendererInitFingerprint.exception + it.mutableMethod.addInstructions( + storyBoardUrlIndex + 1, """ + invoke-static { v$storyboardUrlRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardDecoderRendererSpec(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$storyboardUrlRegister + """ + ) + } ?: throw StoryboardRendererDecoderSpecFingerprint.exception } } 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 new file mode 100644 index 000000000..884d1237b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignatureResourcePatch.kt @@ -0,0 +1,18 @@ +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.youtube.misc.settings.SettingsPatch + +@Patch(dependencies = [SettingsPatch::class, ResourceMappingPatch::class]) +object SpoofSignatureResourcePatch : ResourcePatch() { + internal var scrubbedPreviewThumbnailResourceId: Long = -1 + + override fun execute(context: ResourceContext) { + scrubbedPreviewThumbnailResourceId = ResourceMappingPatch.resourceMappings.single { + it.type == "id" && it.name == "thumbnail" + }.id + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt similarity index 91% rename from src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt index 1e58bde72..fb4eadced 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplGeneralFingerprint.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -object PlayerResponseModelImplFingerprint : MethodFingerprint( +object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint( returnType = "Ljava/lang/String;", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = emptyList(), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt new file mode 100644 index 000000000..5dbd60c98 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.extensions.containsWideLiteralInstructionValue +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 + +object PlayerResponseModelImplLiveStreamFingerprint : MethodFingerprint( + returnType = "Ljava/lang/String;", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = emptyList(), + opcodes = listOf( + Opcode.RETURN_OBJECT, + Opcode.CONST_4, + Opcode.RETURN_OBJECT + ), + customFingerprint = handler@{ methodDef, _ -> + if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false + + methodDef.containsWideLiteralInstructionValue(70276274) + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevel.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevel.kt new file mode 100644 index 000000000..4b7165a32 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplRecommendedLevel.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.extensions.containsWideLiteralInstructionValue +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 + +object PlayerResponseModelImplRecommendedLevel : MethodFingerprint( + returnType = "I", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = emptyList(), + opcodes = listOf( + Opcode.SGET_OBJECT, + Opcode.IGET, + Opcode.RETURN + ), + customFingerprint = handler@{ methodDef, _ -> + if (!methodDef.definingClass.endsWith("/PlayerResponseModelImpl;")) return@handler false + + methodDef.containsWideLiteralInstructionValue(55735497) + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt new file mode 100644 index 000000000..36bce605d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt @@ -0,0 +1,27 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.youtube.misc.fix.playback.SpoofSignatureResourcePatch +import app.revanced.util.patch.LiteralValueFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +object ScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint( + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + returnType = "V", + parameters = listOf("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I", "I"), + opcodes = listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.INVOKE_VIRTUAL, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.IPUT_OBJECT, // preview imageview + ), + // This resource is used in ~ 40 different locations, but this method has a distinct list of parameters to match to. + literalSupplier = { SpoofSignatureResourcePatch.scrubbedPreviewThumbnailResourceId } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt new file mode 100644 index 000000000..6ced90401 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderRecommendedLevelFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** + * Resolves to the same method as [StoryboardRendererDecoderSpecFingerprint]. + */ +object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT + ), + strings = listOf("#-1#") +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt new file mode 100644 index 000000000..f0905e883 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererDecoderSpecFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +/** +* Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint]. +*/ +object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;"), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, // First instruction of the method. + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.CONST_4, + Opcode.IF_NEZ, + ), + strings = listOf("#-1#") +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererInitFingerprint.kt deleted file mode 100644 index 79ca910e3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardRendererInitFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.fingerprint.MethodFingerprint -import com.android.tools.smali.dexlib2.Opcode - -object StoryboardRendererInitFingerprint : MethodFingerprint( - strings = listOf("#-1#"), - opcodes = listOf( - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT - ) -) 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 14b3f78c7..7a442718d 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 @@ -10,8 +10,8 @@ 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.youtube.misc.integrations.IntegrationsPatch -import app.revanced.patches.youtube.misc.links.fingerprints.OpenLinksDirectlyPrimaryFingerprint -import app.revanced.patches.youtube.misc.links.fingerprints.OpenLinksDirectlySecondaryFingerprint +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 com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -23,20 +23,15 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction CompatiblePackage( "com.google.android.youtube", [ - "18.16.37", - "18.19.35", - "18.20.39", - "18.23.35", - "18.29.38", - "18.32.39", - "18.37.36", - "18.38.44" + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] ) object BypassURLRedirectsPatch : BytecodePatch( - setOf(OpenLinksDirectlyPrimaryFingerprint, OpenLinksDirectlySecondaryFingerprint) + setOf(ABUriParserFingerprint, HTTPUriParserFingerprint) ) { override fun execute(context: BytecodeContext) { SettingsPatch.PreferenceScreen.MISC.addPreferences( @@ -48,14 +43,14 @@ object BypassURLRedirectsPatch : BytecodePatch( ) ) - arrayOf( - OpenLinksDirectlyPrimaryFingerprint, - OpenLinksDirectlySecondaryFingerprint - ).map { - it.result ?: throw it.exception - }.forEach { result -> + mapOf( + ABUriParserFingerprint to 7, // Offset to Uri.parse. + HTTPUriParserFingerprint to 0 // Offset to Uri.parse. + ).map { (fingerprint, offset) -> + (fingerprint.result ?: throw fingerprint.exception) to offset + }.forEach { (result, offset) -> result.mutableMethod.apply { - val insertIndex = result.scanResult.patternScanResult!!.startIndex + val insertIndex = result.scanResult.patternScanResult!!.startIndex + offset val uriStringRegister = getInstruction(insertIndex).registerC replaceInstruction( 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 92166fa35..fdccbf2c9 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 @@ -30,7 +30,10 @@ import com.android.tools.smali.dexlib2.iface.reference.StringReference "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/OpenLinksDirectlyPrimaryFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt similarity index 53% rename from src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/OpenLinksDirectlyPrimaryFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt index 7aad8d30f..3bd70fbbd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/OpenLinksDirectlyPrimaryFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/ABUriParserFingerprint.kt @@ -5,16 +5,25 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -object OpenLinksDirectlyPrimaryFingerprint : MethodFingerprint( +object ABUriParserFingerprint : MethodFingerprint( returnType = "Ljava/lang/Object", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("Ljava/lang/Object"), opcodes = listOf( + Opcode.RETURN_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.RETURN_OBJECT, + Opcode.CHECK_CAST, Opcode.INVOKE_STATIC, Opcode.MOVE_RESULT_OBJECT, Opcode.RETURN_OBJECT, - Opcode.CHECK_CAST, - Opcode.SGET, - Opcode.SGET_OBJECT - ) + Opcode.CHECK_CAST + ), + customFingerprint = { methodDef, classDef -> + // This method is always called "a" because this kind of class always has a single method. + methodDef.name == "a" && classDef.methods.count() == 3 + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/OpenLinksDirectlySecondaryFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/OpenLinksDirectlySecondaryFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt index 47a930050..b9dd490cd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/OpenLinksDirectlySecondaryFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/fingerprints/HTTPUriParserFingerprint.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode -object OpenLinksDirectlySecondaryFingerprint : MethodFingerprint( +object HTTPUriParserFingerprint : MethodFingerprint( returnType = "Landroid/net/Uri", accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("Ljava/lang/String"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGBytecodePatch.kt index 9d33bcfe4..1a8a04425 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGBytecodePatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.all.misc.packagename.ChangePackageNamePatch import app.revanced.patches.shared.fingerprints.WatchWhileActivityFingerprint import app.revanced.patches.youtube.layout.buttons.cast.HideCastButtonPatch import app.revanced.patches.youtube.misc.fix.playback.ClientSpoofPatch @@ -16,6 +17,7 @@ import app.revanced.util.microg.MicroGBytecodeHelper name = "Vanced MicroG support", description = "Allows YouTube to run without root and under a different package name with Vanced MicroG.", dependencies = [ + ChangePackageNamePatch::class, MicroGResourcePatch::class, HideCastButtonPatch::class, ClientSpoofPatch::class @@ -30,7 +32,10 @@ import app.revanced.util.microg.MicroGBytecodeHelper "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] @@ -48,18 +53,20 @@ object MicroGBytecodePatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext) { + val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(REVANCED_PACKAGE_NAME) + // apply common microG patch MicroGBytecodeHelper.patchBytecode( context, arrayOf( MicroGBytecodeHelper.packageNameTransform( PACKAGE_NAME, - REVANCED_PACKAGE_NAME + packageName ) ), MicroGBytecodeHelper.PrimeMethodTransformationData( PrimeFingerprint, PACKAGE_NAME, - REVANCED_PACKAGE_NAME + packageName ), listOf( ServiceCheckFingerprint, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGResourcePatch.kt index 43f057572..c38cb0ba2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/MicroGResourcePatch.kt @@ -3,6 +3,7 @@ package app.revanced.patches.youtube.misc.microg 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.packagename.ChangePackageNamePatch import app.revanced.patches.shared.settings.preference.impl.Preference import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME @@ -15,7 +16,12 @@ import app.revanced.util.microg.Constants.MICROG_VENDOR import app.revanced.util.microg.MicroGManifestHelper import app.revanced.util.microg.MicroGResourceHelper -@Patch(dependencies = [SettingsPatch::class]) +@Patch( + dependencies = [ + SettingsPatch::class, + ChangePackageNamePatch::class + ] +) object MicroGResourcePatch : ResourcePatch() { override fun execute(context: ResourceContext) { SettingsPatch.addPreference( @@ -25,13 +31,16 @@ object MicroGResourcePatch : ResourcePatch() { Preference.Intent("$MICROG_VENDOR.android.gms", "", "org.microg.gms.ui.SettingsActivity") ) ) - SettingsPatch.renameIntentsTargetPackage(REVANCED_PACKAGE_NAME) + + val packageName = ChangePackageNamePatch.setOrGetFallbackPackageName(REVANCED_PACKAGE_NAME) + + SettingsPatch.renameIntentsTargetPackage(packageName) // update manifest MicroGResourceHelper.patchManifest( context, PACKAGE_NAME, - REVANCED_PACKAGE_NAME, + packageName, REVANCED_APP_NAME ) 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 4ffd018d0..6e50ab974 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 @@ -35,7 +35,10 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 new file mode 100644 index 000000000..616b544b5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatch.kt @@ -0,0 +1,73 @@ +package app.revanced.patches.youtube.misc.privacy + +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.youtube.misc.integrations.IntegrationsPatch +import app.revanced.patches.youtube.misc.privacy.fingerprints.CopyTextFingerprint +import app.revanced.patches.youtube.misc.settings.SettingsPatch +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction + +@Patch( + name = "Remove tracking query parameter", + description = "Remove the tracking query parameter from links.", + dependencies = [IntegrationsPatch::class, SettingsPatch::class], + compatiblePackages = [ + CompatiblePackage( + "com.google.android.youtube", + [ + "18.43.45", + "18.44.41", + "18.45.41" + ] + ) + ] +) +@Suppress("unused") +object RemoveTrackingQueryParameterPatch : BytecodePatch( + setOf(CopyTextFingerprint) +) { + const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/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" + ), + ) + ) + + CopyTextFingerprint.result?.let { + val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 + + it.mutableMethod.apply { + val urlRegister = getInstruction(insertIndex - 2).registerA + + addInstructions( + insertIndex, + """ + invoke-static {v$urlRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->sanitize(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$urlRegister + """ + ) + } + + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/fingerprints/CopyTextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/fingerprints/CopyTextFingerprint.kt new file mode 100644 index 000000000..0375bf482 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/privacy/fingerprints/CopyTextFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.misc.privacy.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +object CopyTextFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L", "Ljava/util/Map;"), + opcodes = listOf( + Opcode.IGET_OBJECT, // Contains the text to copy to be sanitized. + Opcode.CONST_STRING, + Opcode.INVOKE_STATIC, // ClipData.newPlainText + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.RETURN_VOID + ), + strings = listOf("text/plain") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt index 9d77d2d85..4752c0e1b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/RecyclerViewTreeHookPatch.kt @@ -21,7 +21,7 @@ object RecyclerViewTreeHookPatch : BytecodePatch( RecyclerViewTreeObserverFingerprint.result?.let { it.mutableMethod.apply { - val insertIndex = it.scanResult.patternScanResult!!.startIndex + 5 + val insertIndex = it.scanResult.patternScanResult!!.startIndex val recyclerViewParameter = 2 addHook = { classDescriptor -> diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt index c54499c7f..ab1579453 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/recyclerviewtree/hook/fingerprints/RecyclerViewTreeObserverFingerprint.kt @@ -11,11 +11,10 @@ object RecyclerViewTreeObserverFingerprint : MethodFingerprint( opcodes = listOf( Opcode.NEW_INSTANCE, Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.IGET_BOOLEAN, - Opcode.IF_NEZ, - Opcode.INVOKE_VIRTUAL_RANGE, - Opcode.MOVE_RESULT_OBJECT + Opcode.INVOKE_VIRTUAL, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT ), strings = listOf("LithoRVSLCBinder") ) \ No newline at end of file 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 614cfcaf1..0ce02be31 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 @@ -28,7 +28,10 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 7ddab3254..910d6f26a 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 @@ -37,7 +37,10 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] 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 4ced038b2..e38ed5c4a 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 @@ -20,7 +20,10 @@ import app.revanced.patches.youtube.video.speed.remember.RememberPlaybackSpeedPa "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/OldVideoQualityMenuPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/OldVideoQualityMenuPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt index c8ebeebf8..c28c95327 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/OldVideoQualityMenuPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuPatch.kt @@ -13,11 +13,11 @@ import app.revanced.patches.youtube.video.videoqualitymenu.fingerprints.VideoQua import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @Patch( - name = "Old video quality menu", - description = "Shows the old video quality with the advanced video quality options instead of the new one.", + name = "Restore old video quality menu", + description = "Restores the old video quality with advanced video quality options.", dependencies = [ IntegrationsPatch::class, - OldVideoQualityMenuResourcePatch::class, + RestoreOldVideoQualityMenuResourcePatch::class, LithoFilterPatch::class, RecyclerViewTreeHookPatch::class ], @@ -30,20 +30,23 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction "18.29.38", "18.32.39", "18.37.36", - "18.38.44" + "18.38.44", + "18.43.45", + "18.44.41", + "18.45.41" ] ) ] ) @Suppress("unused") -object OldVideoQualityMenuPatch : BytecodePatch( +object RestoreOldVideoQualityMenuPatch : BytecodePatch( setOf(VideoQualityMenuViewInflateFingerprint) ) { private const val FILTER_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/VideoQualityMenuFilterPatch;" private const val INTEGRATIONS_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/patches/playback/quality/OldVideoQualityMenuPatch;" + "Lapp/revanced/integrations/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/OldVideoQualityMenuResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt similarity index 71% rename from src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/OldVideoQualityMenuResourcePatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt index 9d7599d99..b16e1066f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/OldVideoQualityMenuResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/RestoreOldVideoQualityMenuResourcePatch.kt @@ -12,16 +12,16 @@ import app.revanced.patches.youtube.misc.settings.SettingsPatch @Patch( dependencies = [SettingsPatch::class, ResourceMappingPatch::class] ) -object OldVideoQualityMenuResourcePatch : ResourcePatch() { +object RestoreOldVideoQualityMenuResourcePatch : ResourcePatch() { internal var videoQualityBottomSheetListFragmentTitle = -1L override fun execute(context: ResourceContext) { SettingsPatch.PreferenceScreen.VIDEO.addPreferences( SwitchPreference( - "revanced_show_old_video_quality_menu", - StringResource("revanced_show_old_video_quality_menu_title", "Show old video quality menu"), - StringResource("revanced_show_old_video_quality_menu_summary_on", "Old video quality menu is shown"), - StringResource("revanced_show_old_video_quality_menu_summary_off", "New video quality menu is hidden") + "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") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt index 2b41427c7..9bd5046a9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoqualitymenu/fingerprints/VideoQualityMenuViewInflateFingerprint.kt @@ -1,7 +1,7 @@ package app.revanced.patches.youtube.video.videoqualitymenu.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patches.youtube.video.videoqualitymenu.OldVideoQualityMenuResourcePatch +import app.revanced.patches.youtube.video.videoqualitymenu.RestoreOldVideoQualityMenuResourcePatch import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -26,5 +26,5 @@ object VideoQualityMenuViewInflateFingerprint : LiteralValueFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST ), - literalSupplier = { OldVideoQualityMenuResourcePatch.videoQualityBottomSheetListFragmentTitle } + literalSupplier = { RestoreOldVideoQualityMenuResourcePatch.videoQualityBottomSheetListFragmentTitle } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/patch/MethodCall.kt b/src/main/kotlin/app/revanced/util/patch/MethodCall.kt index 48a38ad07..1533c1ca7 100644 --- a/src/main/kotlin/app/revanced/util/patch/MethodCall.kt +++ b/src/main/kotlin/app/revanced/util/patch/MethodCall.kt @@ -67,6 +67,7 @@ inline fun fromMethodReference(methodReference: MethodReference) search.definedClassName == methodReference.definingClass && search.methodName == methodReference.name && methodReference.parameterTypes.toTypedArray().contentEquals(search.methodParams) + && search.returnType == methodReference.returnType } inline fun filterMapInstruction35c( diff --git a/src/main/resources/sponsorblock/host/values/strings.xml b/src/main/resources/sponsorblock/host/values/strings.xml index cdda3bf06..f3159afd2 100644 --- a/src/main/resources/sponsorblock/host/values/strings.xml +++ b/src/main/resources/sponsorblock/host/values/strings.xml @@ -75,7 +75,7 @@ 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 + 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