diff --git a/.github/ISSUE_TEMPLATE/bug-issue.yml b/.github/ISSUE_TEMPLATE/bug-issue.yml index 193df90b4..6b98f0483 100644 --- a/.github/ISSUE_TEMPLATE/bug-issue.yml +++ b/.github/ISSUE_TEMPLATE/bug-issue.yml @@ -1,6 +1,6 @@ name: 🐞 Bug report description: Report a very clearly broken issue. -title: 'bug: ' +title: 'bug: ' labels: [bug] body: - type: markdown diff --git a/.github/ISSUE_TEMPLATE/patch-request.yml b/.github/ISSUE_TEMPLATE/patch-request.yml index 53b1373a1..35084c206 100644 --- a/.github/ISSUE_TEMPLATE/patch-request.yml +++ b/.github/ISSUE_TEMPLATE/patch-request.yml @@ -1,6 +1,6 @@ name: ⭐ Patch Request description: Create a detailed patch request. -title: 'feat(patch): ' +title: 'feat: ' labels: [patch-request] body: - type: textarea @@ -24,7 +24,7 @@ body: - type: textarea attributes: label: Motivation - description: Why should your patch request should be considered? What makes it valuable to the community? + description: Why should your patch request be considered? What makes it valuable to the community? validations: required: true - type: checkboxes @@ -38,4 +38,4 @@ body: - label: I have written a short but informative title. required: true - label: I filled out all of the requested information in this issue properly. - required: true \ No newline at end of file + required: true diff --git a/.releaserc b/.releaserc index 3ed71897a..c113646e4 100644 --- a/.releaserc +++ b/.releaserc @@ -7,7 +7,13 @@ } ], "plugins": [ - "@semantic-release/commit-analyzer", + [ + "@semantic-release/commit-analyzer", { + "releaseRules": [ + { "type": "build", "scope": "revanced-patcher", "release": "patch" } + ] + } + ], "@semantic-release/release-notes-generator", "@semantic-release/changelog", "gradle-semantic-release-plugin", diff --git a/CHANGELOG.md b/CHANGELOG.md index a9008310a..de0df6d2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,311 @@ +# [2.174.0-dev.41](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.40...v2.174.0-dev.41) (2023-05-24) + + +### Bug Fixes + +* **youtube/vanced-microg-support:** depend on `client-spoof` patch ([83a4905](https://github.com/revanced/revanced-patches/commit/83a490575c60adf21db926df3013f539c6d33068)) + +# [2.174.0-dev.40](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.39...v2.174.0-dev.40) (2023-05-23) + + +### Bug Fixes + +* **photomath/unlock-plus:** constrain to last working version ([#2232](https://github.com/revanced/revanced-patches/issues/2232)) ([4da268e](https://github.com/revanced/revanced-patches/commit/4da268edc006ea496e3b1efd037676f1c40397da)) + +# [2.174.0-dev.39](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.38...v2.174.0-dev.39) (2023-05-22) + + +### Features + +* **reddit:** remove compatibility version constraints ([#2226](https://github.com/revanced/revanced-patches/issues/2226)) ([f1288e4](https://github.com/revanced/revanced-patches/commit/f1288e4bb8fb1b9f394d73fd814d97db8704b8e0)) + +# [2.174.0-dev.38](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.37...v2.174.0-dev.38) (2023-05-21) + + +### Features + +* **trakt:** add `unlock-pro` patch ([#2210](https://github.com/revanced/revanced-patches/issues/2210)) ([1e8dcae](https://github.com/revanced/revanced-patches/commit/1e8dcae6f540455b8698703bbded5f52fd0c6300)) + +# [2.174.0-dev.37](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.36...v2.174.0-dev.37) (2023-05-21) + + +### Features + +* **reddit:** add `sanitize-sharing-links` patch ([#2192](https://github.com/revanced/revanced-patches/issues/2192)) ([9593e4b](https://github.com/revanced/revanced-patches/commit/9593e4b5db604957545b4ab6747c82fb815ac08b)) + +# [2.174.0-dev.36](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.35...v2.174.0-dev.36) (2023-05-20) + + +### Bug Fixes + +* **twitter:** correctly resolve to integrations methods ([c655416](https://github.com/revanced/revanced-patches/commit/c655416a91f0a32cfe82b1384f5958cace891833)) + +# [2.174.0-dev.35](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.34...v2.174.0-dev.35) (2023-05-19) + + +### Bug Fixes + +* **youtube/minimized-playback:** update settings description ([#2191](https://github.com/revanced/revanced-patches/issues/2191)) ([a561a9a](https://github.com/revanced/revanced-patches/commit/a561a9afc233e466459546fcc8452800ec56e057)) +* **youtube/settings:** fix non functional back button in settings ([#2178](https://github.com/revanced/revanced-patches/issues/2178)) ([46da834](https://github.com/revanced/revanced-patches/commit/46da83430f69b451f971bf5e9261e9d64d1a365c)) + + +### Features + +* add capability to filter from protobuf buffer ([b738b6b](https://github.com/revanced/revanced-patches/commit/b738b6bf3506f222844ef4bca99a91f78d331391)) +* use consistent names for patches ([6347146](https://github.com/revanced/revanced-patches/commit/634714690086168e63d6aa9475893135cb58db68)) +* **youtube/copy-video-url:** add tap and hold functionality to copy video url buttons ([#2174](https://github.com/revanced/revanced-patches/issues/2174)) ([95bbf46](https://github.com/revanced/revanced-patches/commit/95bbf46e77a608bd7ba8f0073d50fef01012d4df)) +* **youtube/hide-shorts-components:** hide navigation bar ([24f376a](https://github.com/revanced/revanced-patches/commit/24f376a4b8d6bdccc32ffff0d983f22eb4940791)) +* **youtube:** add `hide-shorts-components` patch ([64868f4](https://github.com/revanced/revanced-patches/commit/64868f41be9f567cb54d9214fafbf849d08b64d2)) +* **youtube:** constrain patches to `18.16.37` ([758b300](https://github.com/revanced/revanced-patches/commit/758b3005919e11d9dd4f19bf110e9d282f8d1925)) +* **youtube:** support version `18.19.35` ([491f292](https://github.com/revanced/revanced-patches/commit/491f292182a419cb5399de768560ae4daa7c86cb)) + +# [2.174.0-dev.34](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.33...v2.174.0-dev.34) (2023-05-16) + + +### Features + +* **vsco:** add `unlock-pro` patch ([#2168](https://github.com/revanced/revanced-patches/issues/2168)) ([7ffd1a0](https://github.com/revanced/revanced-patches/commit/7ffd1a09a7bcf09bc7e7d5f3c8c8613ca34c8c59)) + +# [2.174.0-dev.33](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.32...v2.174.0-dev.33) (2023-05-16) + + +### Bug Fixes + +* **youtube/spoof-signature-verification:** adjusting summary text ([#2169](https://github.com/revanced/revanced-patches/issues/2169)) ([4ccb1ee](https://github.com/revanced/revanced-patches/commit/4ccb1ee0b988bc0ddd6a0c986975b17caa828770)) + +# [2.174.0-dev.32](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.31...v2.174.0-dev.32) (2023-05-16) + + +### Bug Fixes + +* **youtube/sponsorblock:** fix toast shown when scrubbing thru a paused video ([#2152](https://github.com/revanced/revanced-patches/issues/2152)) ([c6c23ff](https://github.com/revanced/revanced-patches/commit/c6c23ff0d9a18e3ef3d4b9b28ffa562a2eceb58b)) + + +### Features + +* **youtube:** add options to disable toasts on connection error ([#2159](https://github.com/revanced/revanced-patches/issues/2159)) ([99916ae](https://github.com/revanced/revanced-patches/commit/99916aefaaea3b94e94e2901d70493fdb18a3dab)) + +# [2.174.0-dev.31](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.30...v2.174.0-dev.31) (2023-05-16) + + +### Features + +* **candylinkvpn:** add `unlock-pro` patch ([#2157](https://github.com/revanced/revanced-patches/issues/2157)) ([7159f86](https://github.com/revanced/revanced-patches/commit/7159f867801300d4ae32937743de59421de76238)) +* **messenger:** add `disable-typing-indicator` patch ([#2115](https://github.com/revanced/revanced-patches/issues/2115)) ([5d1de4f](https://github.com/revanced/revanced-patches/commit/5d1de4f4eab83e61cfc1c4aaee74179afcb9431f)) + +# [2.174.0-dev.30](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.29...v2.174.0-dev.30) (2023-05-16) + + +### Features + +* **youtube/hide-filter-bar:** add `PreferenceScreen` summary ([2bba5f7](https://github.com/revanced/revanced-patches/commit/2bba5f72fae06e352d2984fea7c8cc65d38ed221)) + +# [2.174.0-dev.29](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.28...v2.174.0-dev.29) (2023-05-16) + + +### Features + +* **youtube/downloads:** improve patch description ([e0f6452](https://github.com/revanced/revanced-patches/commit/e0f64520d0235ea219f1965ba34b7e52ded9c1d9)) + +# [2.174.0-dev.28](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.27...v2.174.0-dev.28) (2023-05-15) + + +### Bug Fixes + +* **youtube:** add missing compatibility annotations for `theme` and `hide-load-more-button` ([#2150](https://github.com/revanced/revanced-patches/issues/2150)) ([78803f8](https://github.com/revanced/revanced-patches/commit/78803f8ea85684e4c69e75b676fa40bae8760957)) + + +### Features + +* **youtube:** import / export of revanced settings ([#2077](https://github.com/revanced/revanced-patches/issues/2077)) ([b59cb3e](https://github.com/revanced/revanced-patches/commit/b59cb3ed60293aaf81067ff3469863add09c6b13)) + +# [2.174.0-dev.27](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.26...v2.174.0-dev.27) (2023-05-14) + + +### Bug Fixes + +* **youtube/video-speed:** add compatibility annotation ([#2156](https://github.com/revanced/revanced-patches/issues/2156)) ([ffa2e5d](https://github.com/revanced/revanced-patches/commit/ffa2e5d7eb0b90bb5c7a6854bab4caf9f810d917)) + +# [2.174.0-dev.26](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.25...v2.174.0-dev.26) (2023-05-14) + + +### Bug Fixes + +* **youtube/return-youtube-dislikes:** fix temporarily frozen video after opening a shorts ([#2126](https://github.com/revanced/revanced-patches/issues/2126)) ([e0877e3](https://github.com/revanced/revanced-patches/commit/e0877e33814ba396e64e18a577064aa5be952413)) + +# [2.174.0-dev.25](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.24...v2.174.0-dev.25) (2023-05-14) + +# [2.174.0-dev.24](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.23...v2.174.0-dev.24) (2023-05-13) + + +### Features + +* **twitch/auto-claim-channel-points:** use correct casing for "Channel Points" ([#2138](https://github.com/revanced/revanced-patches/issues/2138)) ([76a3bf2](https://github.com/revanced/revanced-patches/commit/76a3bf23b5e5591ae635e612af07cbbd78d49f53)) + +# [2.174.0-dev.23](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.22...v2.174.0-dev.23) (2023-05-13) + + +### Bug Fixes + +* **youtube/custom-video-speed:** add missing class for `video-speeds` patch ([#2137](https://github.com/revanced/revanced-patches/issues/2137)) ([758ef42](https://github.com/revanced/revanced-patches/commit/758ef42f9cd36d665b1737b67bcdde22d3e3eb98)) + +# [2.174.0-dev.22](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.21...v2.174.0-dev.22) (2023-05-12) + + +### Features + +* **youtube:** move video settings to `Video` settings category ([#2010](https://github.com/revanced/revanced-patches/issues/2010)) ([f4b9180](https://github.com/revanced/revanced-patches/commit/f4b918075a70d1a4ed9ac7e9c1f0e0acd1c77404)) + +# [2.174.0-dev.21](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.20...v2.174.0-dev.21) (2023-05-12) + + +### Features + +* **twitch:** add `auto-claim-channel-points` patch ([#2131](https://github.com/revanced/revanced-patches/issues/2131)) ([80fb670](https://github.com/revanced/revanced-patches/commit/80fb6701b52a8c6c6bada5546dffe3438f0e4879)) + +# [2.174.0-dev.20](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.19...v2.174.0-dev.20) (2023-05-12) + + +### Features + +* **youtube:** add `hide-filter-bar` patch ([6cc5f61](https://github.com/revanced/revanced-patches/commit/6cc5f61e0712fe25cd45b137773decaf4b9bb582)) + +# [2.174.0-dev.19](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.18...v2.174.0-dev.19) (2023-05-11) + + +### Features + +* **youtube/video-speed:** change custom video speeds inside app settings ([#2114](https://github.com/revanced/revanced-patches/issues/2114)) ([d97815a](https://github.com/revanced/revanced-patches/commit/d97815af18e645fd0fa087db0174bcc2a771ec72)) + +# [2.174.0-dev.18](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.17...v2.174.0-dev.18) (2023-05-11) + + +### Bug Fixes + +* **youtube/theme:** apply custom seekbar color to video thumbnails ([#2085](https://github.com/revanced/revanced-patches/issues/2085)) ([d497027](https://github.com/revanced/revanced-patches/commit/d4970273ad10f62cd9455ef9b847c686147f7dca)) + +# [2.174.0-dev.17](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.16...v2.174.0-dev.17) (2023-05-09) + + +### Bug Fixes + +* **youtube/remember-video-quality:** fix default video quality/speed being applied when resuming app. ([#2112](https://github.com/revanced/revanced-patches/issues/2112)) ([f68a41c](https://github.com/revanced/revanced-patches/commit/f68a41ce9f9a78818d3f28b069e70b8c66125f53)) + +# [2.174.0-dev.16](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.15...v2.174.0-dev.16) (2023-05-08) + + +### Bug Fixes + +* check for opcode type `CONST` ([e5bb63c](https://github.com/revanced/revanced-patches/commit/e5bb63c7ab4427b6116de4a999be306e0f3cf12e)) + +# [2.174.0-dev.15](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.14...v2.174.0-dev.15) (2023-05-08) + + +### Features + +* **messenger:** add `disable-switching-emoji-to-sticker-in-message-input-field` patch ([#2099](https://github.com/revanced/revanced-patches/issues/2099)) ([ac5532a](https://github.com/revanced/revanced-patches/commit/ac5532a65c353b1964d9b7d990341fc7362e510d)) + +# [2.174.0-dev.14](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.13...v2.174.0-dev.14) (2023-05-07) + + +### Features + +* **youtube/hide-player-overlay:** make it toggleable in settings ([#2044](https://github.com/revanced/revanced-patches/issues/2044)) ([f693d55](https://github.com/revanced/revanced-patches/commit/f693d55caf1e0b72bb1f4c39b1eeb59436191e02)) + +# [2.174.0-dev.13](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.12...v2.174.0-dev.13) (2023-05-07) + + +### Bug Fixes + +* account fo breaking changes from ReVanced Patcher ([#2103](https://github.com/revanced/revanced-patches/issues/2103)) ([5be25cd](https://github.com/revanced/revanced-patches/commit/5be25cde4b34d58ced35a7edbb499477b538b748)) + +# [2.174.0-dev.12](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.11...v2.174.0-dev.12) (2023-05-07) + + +### Bug Fixes + +* **readme-generator:** attempt sorting versions with `FlexVer` ([#2059](https://github.com/revanced/revanced-patches/issues/2059)) ([a54c464](https://github.com/revanced/revanced-patches/commit/a54c464522fa2a6a2d2525c8cb0ec961c2cc771c)) + +# [2.174.0-dev.11](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.10...v2.174.0-dev.11) (2023-05-07) + +# [2.174.0-dev.10](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.9...v2.174.0-dev.10) (2023-05-07) + + +### Bug Fixes + +* incorrect instruction offsets ([42a5a38](https://github.com/revanced/revanced-patches/commit/42a5a387da3c53c579234a44c124ab0ba26117cb)) +* incorrect smali syntax ([4e74a80](https://github.com/revanced/revanced-patches/commit/4e74a800c311d7acb2c2ddb492b43747db8a8def)) + +# [2.174.0-dev.9](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.8...v2.174.0-dev.9) (2023-05-07) + + +### Bug Fixes + +* incorrect cast of instruction ([fb94a1c](https://github.com/revanced/revanced-patches/commit/fb94a1cb48e8952981e2f9146eb90ee92a517b2e)) + +# [2.174.0-dev.8](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.7...v2.174.0-dev.8) (2023-05-07) + + +### Bug Fixes + +* **youtube/integrations:** allow playback of embedded videos ([#2092](https://github.com/revanced/revanced-patches/issues/2092)) ([8a43d75](https://github.com/revanced/revanced-patches/commit/8a43d75e2db63c47bb9ad1b75027df0868c094e5)) + +# [2.174.0-dev.7](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.6...v2.174.0-dev.7) (2023-05-07) + + +### Features + +* **syncforreddit:** add `disable-ads` patch ([#2066](https://github.com/revanced/revanced-patches/issues/2066)) ([c1de5d6](https://github.com/revanced/revanced-patches/commit/c1de5d6e433263b9a17305fa1c65807921594731)) + +# [2.174.0-dev.6](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.5...v2.174.0-dev.6) (2023-05-07) + + +### Features + +* **youtube:** `hide-load-more-button` patch ([#2078](https://github.com/revanced/revanced-patches/issues/2078)) ([7170802](https://github.com/revanced/revanced-patches/commit/71708022a06453f6f56c19d686fc505286523391)) + +# [2.174.0-dev.5](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.4...v2.174.0-dev.5) (2023-05-07) + + +### Bug Fixes + +* **spotify/disable-capture-restriction:** make compatible with latest versions ([#2095](https://github.com/revanced/revanced-patches/issues/2095)) ([e48f127](https://github.com/revanced/revanced-patches/commit/e48f1278da2a9d82e70be41fa2c4c480c574816b)) + +# [2.174.0-dev.4](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.3...v2.174.0-dev.4) (2023-05-07) + + +### Bug Fixes + +* **youtube/theme:** move options out of dependency patch ([a953448](https://github.com/revanced/revanced-patches/commit/a95344879c2ac2cd6da8ce0273dcb05e8a35d2ec)) + + +### Features + +* improve structure of `README` ([279b193](https://github.com/revanced/revanced-patches/commit/279b193b687ad9cba44ab9c2a88d2ce06be0bbf0)) + +# [2.174.0-dev.3](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.2...v2.174.0-dev.3) (2023-05-06) + +# [2.174.0-dev.2](https://github.com/revanced/revanced-patches/compare/v2.174.0-dev.1...v2.174.0-dev.2) (2023-05-03) + + +### Features + +* **patch:** bump compatibility ([#2060](https://github.com/revanced/revanced-patches/issues/2060)) ([f86836d](https://github.com/revanced/revanced-patches/commit/f86836d6295db9eb8c59916deaa991b4d99e96be)) + +# [2.174.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.173.1-dev.1...v2.174.0-dev.1) (2023-05-03) + + +### Features + +* **youtube/settings:** add reset button to edit preference dialog ([#2047](https://github.com/revanced/revanced-patches/issues/2047)) ([ede765a](https://github.com/revanced/revanced-patches/commit/ede765ae3c506909ee8a99517b99b6f5f113f01a)) + +## [2.173.1-dev.1](https://github.com/revanced/revanced-patches/compare/v2.173.0...v2.173.1-dev.1) (2023-05-03) + + +### Bug Fixes + +* **youtube/sponsorblock:** fix skip button in wrong location when full screen and comments visible ([#2051](https://github.com/revanced/revanced-patches/issues/2051)) ([30a954c](https://github.com/revanced/revanced-patches/commit/30a954cac83a66fbb25589edc487797ea5f19986)) + # [2.173.0](https://github.com/revanced/revanced-patches/compare/v2.172.0...v2.173.0) (2023-05-02) diff --git a/README-template.md b/README-template.md index f9ddf51ba..5f21d12d5 100644 --- a/README-template.md +++ b/README-template.md @@ -1,11 +1,13 @@ -## 🧩 Patches +## 🧩 ReVanced Patches -The official Patch bundle provided by ReVanced and the community. +The official ReVanced Patches. -> Looking for the JSON variant of this? [Click here](patches.json). +## 📋 List of patches in this repository {{ table }} +> Looking for the JSON variant of this? [Click here](patches.json). + ## 📝 JSON Format This section explains the JSON format for the [patches.json](patches.json) file. @@ -64,7 +66,6 @@ Example: "description": "Enables a custom theme.", "version": "0.0.1", "excluded": false, - "deprecated": false, "options": [ { "key": "theme", @@ -91,7 +92,6 @@ Example: "description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).", "version": "0.0.1", "excluded": false, - "deprecated": false, "options": [ { "key": "appName", diff --git a/README.md b/README.md index febfeb01f..ac0cf2280 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,69 @@ -## 🧩 Patches +## 🧩 ReVanced Patches -The official Patch bundle provided by ReVanced and the community. +The official ReVanced Patches. -> Looking for the JSON variant of this? [Click here](patches.json). +## 📋 List of patches in this repository ### [📦 `com.google.android.youtube`](https://play.google.com/store/apps/details?id=com.google.android.youtube) <details> | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| -| `always-autorepeat` | Always repeats the playing video again. | 18.16.37 | -| `client-spoof` | Spoofs a patched client to allow playback. | 18.16.37 | -| `comments` | Hides components related to comments. | 18.16.37 | -| `copy-video-url` | Adds buttons in player to copy video links. | 18.16.37 | +| `always-autorepeat` | Always repeats the playing video again. | 18.19.35 | +| `client-spoof` | Spoofs a patched client to allow playback. | 18.19.35 | +| `comments` | Hides components related to comments. | 18.19.35 | +| `copy-video-url` | Adds buttons in player to copy video links. | 18.19.35 | | `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all | -| `custom-video-buffer` | Lets you change the buffers of videos. | 18.16.37 | -| `custom-video-speed` | Adds more video speed options. | 18.16.37 | -| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.16.37 | -| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.16.37 | -| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.16.37 | -| `disable-shorts-on-startup` | Disables playing YouTube Shorts when launching YouTube. | 18.16.37 | +| `custom-video-buffer` | Lets you change the buffers of videos. | 18.19.35 | +| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 18.19.35 | +| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 18.19.35 | +| `disable-player-popup-panels` | Disables panels from appearing automatically when going into fullscreen (playlist or live chat). | 18.19.35 | +| `disable-shorts-on-startup` | Disables playing YouTube Shorts when launching YouTube. | 18.19.35 | | `disable-zoom-haptics` | Disables haptics when zooming. | all | -| `downloads` | Enables downloading music and videos from YouTube. | 18.16.37 | +| `downloads` | Adds a download button to the YouTube video player. | 18.19.35 | | `enable-debugging` | Adds debugging options. | all | -| `general-ads` | Removes general ads. | 18.16.37 | -| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.16.37 | -| `hide-album-cards` | Hides the album cards below the artist description. | 18.16.37 | -| `hide-artist-card` | Hides the artist card below the searchbar. | 18.16.37 | -| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.16.37 | -| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.16.37 | -| `hide-captions-button` | Hides the captions button on video player. | 18.16.37 | +| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 18.19.35 | +| `hide-ads` | Removes general ads. | 18.19.35 | +| `hide-album-cards` | Hides the album cards below the artist description. | 18.19.35 | +| `hide-artist-card` | Hides the artist card below the searchbar. | 18.19.35 | +| `hide-autoplay-button` | Hides the autoplay button in the video player. | 18.19.35 | +| `hide-breaking-news-shelf` | Hides the breaking news shelf on the homepage tab. | 18.19.35 | +| `hide-captions-button` | Hides the captions button on video player. | 18.19.35 | | `hide-cast-button` | Hides the cast button in the video player. | all | -| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.16.37 | -| `hide-email-address` | Hides the email address in the account switcher. | 18.16.37 | -| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.16.37 | -| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.16.37 | -| `hide-get-premium` | Hides advertisement for YouTube Premium under the video player. | 18.16.37 | -| `hide-info-cards` | Hides info cards in videos. | 18.16.37 | -| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | all | -| `hide-player-overlay` | Hides the dark player overlay when player controls are visible. | all | -| `hide-seekbar` | Hides the seekbar. | 18.16.37 | -| `hide-timestamp` | Hides timestamp in video player. | 18.16.37 | -| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.16.37 | -| `hide-watch-in-vr` | Hides the option to watch in VR from the player settings flyout panel. | 18.16.37 | -| `hide-watermark` | Hides creator's watermarks on videos. | 18.16.37 | -| `minimized-playback` | Enables minimized and background playback. | 18.16.37 | -| `navigation-buttons` | Adds options to hide or change navigation buttons. | 18.16.37 | -| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 18.16.37 | -| `open-links-externally` | Open links outside of the app directly in your browser. | 18.16.37 | +| `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 18.19.35 | +| `hide-email-address` | Hides the email address in the account switcher. | 18.19.35 | +| `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 18.19.35 | +| `hide-filter-bar` | Hides the filter bar in video feeds. | 18.19.35 | +| `hide-floating-microphone-button` | Hides the floating microphone button which appears in search. | 18.19.35 | +| `hide-get-premium` | Hides advertisement for YouTube Premium under the video player. | 18.19.35 | +| `hide-info-cards` | Hides info cards in videos. | 18.19.35 | +| `hide-load-more-button` | Hides the button under videos that loads similar videos. | 18.19.35 | +| `hide-player-buttons` | Adds the option to hide video player previous and next buttons. | 18.19.35 | +| `hide-player-overlay` | Hides the dark background overlay from the player when player controls are visible. | all | +| `hide-seekbar` | Hides the seekbar. | 18.19.35 | +| `hide-shorts-components` | Hides components from YouTube Shorts. | 18.19.35 | +| `hide-timestamp` | Hides timestamp in video player. | 18.19.35 | +| `hide-video-action-buttons` | Adds the options to hide action buttons under a video. | 18.19.35 | +| `hide-watch-in-vr` | Hides the option to watch in VR from the player settings flyout panel. | 18.19.35 | +| `hide-watermark` | Hides creator's watermarks on videos. | 18.19.35 | +| `minimized-playback` | Enables minimized and background playback. | 18.19.35 | +| `navigation-buttons` | Adds options to hide or change navigation buttons. | 18.19.35 | +| `old-quality-layout` | Enables the original video quality flyout in the video player settings. | 18.19.35 | +| `open-links-externally` | Open links outside of the app directly in your browser. | 18.19.35 | | `premium-heading` | Shows premium branding on the home screen. | all | -| `remember-playback-speed` | Adds the ability to remember the playback speed you chose in the video playback speed flyout. | 18.16.37 | -| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.16.37 | -| `remove-player-button-background` | Removes the background from the video player buttons. | 18.16.37 | -| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.16.37 | -| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.16.37 | -| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.16.37 | -| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.16.37 | -| `swipe-controls` | Adds volume and brightness swipe controls. | 18.16.37 | -| `tablet-mini-player` | Enables the tablet mini player layout. | 18.16.37 | +| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 18.19.35 | +| `remove-player-button-background` | Removes the background from the video player buttons. | 18.19.35 | +| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 18.19.35 | +| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 18.19.35 | +| `sponsorblock` | Integrates SponsorBlock which allows skipping video segments such as sponsored content. | 18.19.35 | +| `spoof-app-version` | Tricks YouTube into thinking, you are running an older version of the app. One of the side effects also includes restoring the old UI. | 18.19.35 | +| `swipe-controls` | Adds volume and brightness swipe controls. | 18.19.35 | +| `tablet-mini-player` | Enables the tablet mini player layout. | 18.19.35 | | `theme` | Applies a custom theme. | all | -| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.16.37 | -| `video-ads` | Removes ads in the video player. | 18.16.37 | -| `wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.16.37 | +| `vanced-microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 18.19.35 | +| `video-ads` | Removes ads in the video player. | 18.19.35 | +| `video-speed` | Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout. | 18.19.35 | +| `wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 18.19.35 | </details> ### [📦 `com.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music) @@ -119,6 +121,7 @@ The official Patch bundle provided by ReVanced and the community. | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| +| `auto-claim-channel-points` | Automatically claim Channel Points. | all | | `block-audio-ads` | Blocks audio ads in streams and VODs. | 14.6.1 | | `block-embedded-ads` | Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker. | 14.6.1 | | `block-video-ads` | Blocks video ads in streams and VODs. | 14.6.1 | @@ -138,6 +141,17 @@ The official Patch bundle provided by ReVanced and the community. | `hide-views-stats` | Hides the view stats under tweets. | 9.71.0-release.0 | </details> +### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `hide-ads` | Removes general ads from the Reddit frontpage and subreddits. | all | +| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | all | +| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all | +| `sanitize-sharing-links` | Removes (tracking) query parameters from the URLs when sharing links. | all | +</details> + ### [📦 `com.spotify.music`](https://play.google.com/store/apps/details?id=com.spotify.music) <details> @@ -148,14 +162,14 @@ The official Patch bundle provided by ReVanced and the community. | `spotify-theme` | Applies a custom theme. | all | </details> -### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage) +### [📦 `com.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca) <details> | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| -| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | 2023.12.0 | -| `hide-subreddit-banner` | Hides banner ads from comments on subreddits. | 2023.12.0 | -| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all | +| `disable-switching-emoji-to-sticker-in-message-input-field` | Disables switching from emoji to sticker search mode in message input field | all | +| `disable-typing-indicator` | Disables the indicator while typing a message | all | +| `hide-inbox-ads` | Hides ads in inbox. | all | </details> ### [📦 `at.gv.bmf.bmf2go`](https://play.google.com/store/apps/details?id=at.gv.bmf.bmf2go) @@ -176,6 +190,14 @@ The official Patch bundle provided by ReVanced and the community. | `spoof-signature` | Spoofs the signature of the app. | all | </details> +### [📦 `com.laurencedawson.reddit_sync`](https://play.google.com/store/apps/details?id=com.laurencedawson.reddit_sync) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `disable-ads` | Disables ads. | all | +</details> + ### [📦 `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit) <details> @@ -208,14 +230,6 @@ The official Patch bundle provided by ReVanced and the community. | `hide-ads` | Removes general ads. | all | </details> -### [📦 `com.facebook.orca`](https://play.google.com/store/apps/details?id=com.facebook.orca) -<details> - -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `hide-inbox-ads` | Hides ads in inbox. | all | -</details> - ### [📦 `com.instagram.android`](https://play.google.com/store/apps/details?id=com.instagram.android) <details> @@ -285,7 +299,7 @@ The official Patch bundle provided by ReVanced and the community. | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| -| `unlock-plus` | Unlocks plus features. | 8.9.0 | +| `unlock-plus` | Unlocks plus features. | 8.20.0 | </details> ### [📦 `io.yuka.android`](https://play.google.com/store/apps/details?id=io.yuka.android) @@ -304,30 +318,6 @@ The official Patch bundle provided by ReVanced and the community. | `unlock-prime` | Unlocks Nova Prime and all functions of the app. | all | </details> -### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android) -<details> - -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks all pro features. | all | -</details> - -### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses) -<details> - -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks all professional features. | 3.4.9 | -</details> - -### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator) -<details> - -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks pro features. | 4.6364 | -</details> - ### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager) <details> @@ -336,6 +326,14 @@ The official Patch bundle provided by ReVanced and the community. | `unlock-pro` | Unlocks pro features. | all | </details> +### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `unlock-pro` | Unlocks all pro features. | all | +</details> + ### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio) <details> @@ -344,7 +342,15 @@ The official Patch bundle provided by ReVanced and the community. | `unlock-pro` | Unlocks all pro features. | all | </details> -### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx) +### [📦 `tv.trakt.trakt`](https://play.google.com/store/apps/details?id=tv.trakt.trakt) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `unlock-pro` | Unlocks pro features. | all | +</details> + +### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android) <details> | 💊 Patch | 📜 Description | 🏹 Target Version | @@ -352,6 +358,38 @@ The official Patch bundle provided by ReVanced and the community. | `unlock-pro` | Unlocks all pro features. | all | </details> +### [📦 `com.zombodroid.MemeGenerator`](https://play.google.com/store/apps/details?id=com.zombodroid.MemeGenerator) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `unlock-pro` | Unlocks pro features. | 4.6377 | +</details> + +### [📦 `com.candylink.openvpn`](https://play.google.com/store/apps/details?id=com.candylink.openvpn) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `unlock-pro` | Unlocks premium features. | all | +</details> + +### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `unlock-pro` | Unlocks all professional features. | 3.4.9 | +</details> + +### [📦 `com.vsco.cam`](https://play.google.com/store/apps/details?id=com.vsco.cam) +<details> + +| 💊 Patch | 📜 Description | 🏹 Target Version | +|:--------:|:--------------:|:-----------------:| +| `unlock-pro` | Unlocks pro features. | all | +</details> + ### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task) <details> @@ -370,6 +408,8 @@ The official Patch bundle provided by ReVanced and the community. +> Looking for the JSON variant of this? [Click here](patches.json). + ## 📝 JSON Format This section explains the JSON format for the [patches.json](patches.json) file. @@ -428,7 +468,6 @@ Example: "description": "Enables a custom theme.", "version": "0.0.1", "excluded": false, - "deprecated": false, "options": [ { "key": "theme", @@ -455,7 +494,6 @@ Example: "description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).", "version": "0.0.1", "excluded": false, - "deprecated": false, "options": [ { "key": "appName", diff --git a/build.gradle.kts b/build.gradle.kts index dff3d309d..722156d50 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,13 +17,26 @@ repositories { password = githubPassword } } + // Required for FlexVer-Java + maven { + url = uri("https://repo.sleeping.town") + content { + includeGroup("com.unascribed") + } + } } dependencies { - implementation("app.revanced:revanced-patcher:7.0.0") + implementation("app.revanced:revanced-patcher:9.0.0") implementation("app.revanced:multidexlib2:2.5.3-a3836654") // Required for meta implementation("com.google.code.gson:gson:2.10.1") + // Required for FlexVer-Java + implementation("com.unascribed:flexver-java:1.0.2") +} + +kotlin { + jvmToolchain(11) } tasks { diff --git a/gradle.properties b/gradle.properties index 20e8bde3c..1b7355b38 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style = official -version = 2.173.0 +version = 2.174.0-dev.41 diff --git a/patches.json b/patches.json index 6bb9acbaa..f275f8b6a 100644 --- a/patches.json +++ b/patches.json @@ -1 +1 @@ -[{"name":"always-autorepeat","description":"Always repeats the playing video again.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"background-play","description":"Enables playing music in the background.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"block-audio-ads","description":"Blocks audio ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"block-embedded-ads","description":"Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker.","version":"0.0.1","excluded":false,"options":[],"dependencies":["block-video-ads","integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"block-video-ads","description":"Blocks video ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"bypass-certificate-checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52","5.40.51","5.41.50","5.48.52"]}]},{"name":"change-package-name","description":"Changes the package name.","version":"0.0.1","excluded":true,"options":[{"key":"packageName","title":"Package name","description":"The name of the package to rename of the app.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"client-spoof","description":"Spoofs a patched client to allow playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-signature-verification"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"codecs-unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"comments","description":"Hides components related to comments.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","comments-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"compact-header","description":"Hides the music category bar at the top of the homepage.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"copy-video-url","description":"Adds buttons in player to copy video links.","version":"0.0.1","excluded":false,"options":[],"dependencies":["copy-video-url-resource","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"custom-branding","description":"Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).","version":"0.0.1","excluded":false,"options":[{"key":"appName","title":"Application Name","description":"The name of the application it will show on your home screen.","required":true,"choices":null},{"key":"iconPath","title":"App Icon Path","description":"A path containing mipmap resource folders with icons.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"custom-video-buffer","description":"Lets you change the buffers of videos.","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"custom-video-speed","description":"Adds more video speed options.","version":"0.0.1","excluded":false,"options":[{"key":"granularity","title":"Video speed granularity","description":"The granularity of the video speeds. The higher the value, the more speeds will be available.","required":true,"choices":null},{"key":"min","title":"Minimum video speed","description":"The minimum video speed.","required":true,"choices":null},{"key":"max","title":"Maximum video speed","description":"The maximum video speed. Must be greater than the minimum video speed and smaller than 5.","required":true,"choices":null}],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"debug-mode","description":"Enables Twitch\u0027s internal debugging mode.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"disable-ads","description":"Disables ads in HexEditor.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.myprog.hexedit","versions":[]}]},{"name":"disable-auto-captions","description":"Disable forced captions from being automatically enabled.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"disable-capture-restriction","description":"Allows capturing Spotify\u0027s audio output while screen sharing or screen recording.","version":"0.0.2","excluded":false,"options":[],"dependencies":["disable-capture-restriction-resource-patch"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"disable-fullscreen-panels","description":"Disables video description and comments panel in fullscreen view.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"disable-login-requirement","description":"Do not force login.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"disable-player-popup-panels","description":"Disables panels from appearing automatically when going into fullscreen (playlist or live chat).","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"disable-shorts-on-startup","description":"Disables playing YouTube Shorts when launching YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"disable-zoom-haptics","description":"Disables haptics when zooming.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"downloads","description":"Removes download restrictions and changes the default path to download to.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"downloads","description":"Enables downloading music and videos from YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["downloads-resource-patch","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"dynamic-color","description":"Replaces the default Twitter Blue with the users Material You palette.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"enable-android-debugging","description":"Enables Android debugging capabilities.","version":"0.0.1","excluded":true,"options":[{"key":"debuggable","title":"App debugging","description":"Whether to make the app debuggable on Android.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"enable-debugging","description":"Adds debugging options.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings","enable-android-debugging"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"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.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.lite","versions":[]}]},{"name":"exclusive-audio-playback","description":"Enables the option to play music without video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"export-all-activities","description":"Makes all app activities exportable.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"feed-filter","description":"Filters tiktok videos: removing ads, removing livestreams.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"fix-google-login","description":"Allows logging in with a Google account.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"general-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["GeneralAdsResourcePatch","VerticalScrollPatch","FixBackToExitGesturePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"general-reddit-ads","description":"Removes general ads from the Reddit frontpage and subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":["2021.45.0","2022.43.0","2023.05.0","2023.06.0","2023.07.0","2023.07.1","2023.08.0","2023.09.0","2023.09.1","2023.10.0","2023.11.0","2023.12.0"]}]},{"name":"hdr-auto-brightness","description":"Makes the brightness of HDR videos follow the system default.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-ads","description":"Removes ads from Inshorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.nis.app","versions":[]}]},{"name":"hide-ads","description":"Removes ads from TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["VerticalScrollPatch"],"compatiblePackages":[{"name":"com.vanced.android.youtube","versions":[]}]},{"name":"hide-ads","description":"Hides ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-album-cards","description":"Hides the album cards below the artist description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-album-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-artist-card","description":"Hides the artist card below the searchbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-autoplay-button","description":"Hides the autoplay button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-breaking-news-shelf","description":"Hides the breaking news shelf on the homepage tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","breaking-news-shelf-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-captions-button","description":"Hides the captions button on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-cast-button","description":"Hides the cast button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-crowdfunding-box","description":"Hides the crowdfunding box between the player and video description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","crowdfunding-box-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-email-address","description":"Hides the email address in the account switcher.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-email-address-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-endscreen-cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-endscreen-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-floating-microphone-button","description":"Hides the floating microphone button which appears in search.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFloatingMicrophoneButtonResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-get-premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52"]}]},{"name":"hide-get-premium","description":"Hides advertisement for YouTube Premium under the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.15.40","18.16.37"]}]},{"name":"hide-inbox-ads","description":"Hides ads in inbox.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"hide-info-cards","description":"Hides info cards in videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","HideInfocardsResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-player-buttons","description":"Adds the option to hide video player previous and next buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-player-overlay","description":"Hides the dark player overlay when player controls are visible.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-premium-navbar","description":"Removes the premium tab from the navbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"hide-recommended-users","description":"Hides recommended users.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-seekbar","description":"Hides the seekbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-subreddit-banner","description":"Hides banner ads from comments on subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":["2023.05.0","2023.06.0","2023.07.0","2023.07.1","2023.08.0","2023.09.0","2023.09.1","2023.10.0","2023.11.0","2023.12.0"]}]},{"name":"hide-timeline-ads","description":"Removes ads from the timeline.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.instagram.android","versions":[]}]},{"name":"hide-timestamp","description":"Hides timestamp in video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-video-action-buttons","description":"Adds the options to hide action buttons under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-views-stats","description":"Hides the view stats under tweets.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideViewsBytecodePatch"],"compatiblePackages":[{"name":"com.twitter.android","versions":["9.69.1-release.0","9.71.0-release.0"]}]},{"name":"hide-watch-in-vr","description":"Hides the option to watch in VR from the player settings flyout panel.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"hide-watermark","description":"Hides creator\u0027s watermarks on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"minimized-playback","description":"Enables minimized and background playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"minimized-playback-music","description":"Enables minimized playback on Kids music.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-microg-support","description":"Allows YouTube Music ReVanced to run without root and under a different package name.","version":"0.0.2","excluded":false,"options":[],"dependencies":["music-microg-resource-patch"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-video-ads","description":"Removes ads in the music player.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"navigation-buttons","description":"Adds options to hide or change navigation buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"old-quality-layout","description":"Enables the original video quality flyout in the video player settings","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"open-links-externally","description":"Open links outside of the app directly in your browser.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"playback-speed","description":"Enables the playback speed option for all videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"predictive-back-gesture","description":"Enables the predictive back gesture introduced on Android 13.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"premium-heading","description":"Shows premium branding on the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"premium-icon-reddit","description":"Unlocks premium Reddit app icons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"premium-unlock","description":"Unlocks premium functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.citra.citra_emu","versions":[]},{"name":"org.citra.citra_emu.canary","versions":[]}]},{"name":"pro-unlock","description":"Unlocks pro-only functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}]},{"name":"promo-code-unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-cert-patch"],"compatiblePackages":[{"name":"de.dwd.warnapp","versions":[]}]},{"name":"remember-playback-speed","description":"Adds the ability to remember the playback speed you chose in the video playback speed flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","video-id-hook","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.08.37","18.15.40","18.16.37"]}]},{"name":"remember-video-quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.08.37","18.15.40","18.16.37"]}]},{"name":"remove-ads","description":"Removes all ads from the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":[]}]},{"name":"remove-bootloader-detection","description":"Removes the check for an unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":["2.2.0"]}]},{"name":"remove-broadcasts-restriction","description":"Enables starting/stopping NetGuard via broadcasts.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"eu.faircode.netguard","versions":[]}]},{"name":"remove-player-button-background","description":"Removes the background from the video player buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":["2.2.0"]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions and unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"remove-screenshot-restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"return-youtube-dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","return-youtube-dislike-resource-patch","player-type-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.15.40","18.16.37"]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"settings","description":"Adds settings menu to Twitch.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings-resource-patch"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"settings","description":"Adds ReVanced settings to TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"show-deleted-messages","description":"Shows deleted chat messages behind a clickable spoiler.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"show-seekbar","description":"Shows progress bar for all video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sim-spoof","description":"Spoofs the information which is retrieved from the sim-card.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"sponsorblock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","video-information","player-type-hook","player-controls-bytecode-patch","sponsorblock-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.08.37","18.15.40","18.16.37"]}]},{"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.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"spoof-signature","description":"Spoofs the signature of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"spoof-wifi-connection","description":"Spoofs an existing Wi-Fi connection.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"spotify-theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"backgroundColor","title":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentColor","title":"Accent color","description":"The accent color (\u0027spotify green\u0027 by default). Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentPressedColor","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,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"swipe-controls","description":"Adds volume and brightness swipe controls.","version":"0.0.3","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","swipe-controls-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"tablet-mini-player","description":"Enables the tablet mini player layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.15.40","18.16.37"]}]},{"name":"tasteBuilder-remover","description":"Removes the \"Tell us which artists you like\" card from the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[],"dependencies":["theme-litho-components","ThemeResourcePatch","integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"unlock-paid-widgets","description":"Unlocks paid widgets of the app","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.dci.dev.androidtwelvewidgets","versions":[]}]},{"name":"unlock-plus","description":"Unlocks plus features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureDetectionPatch"],"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.6.0","8.7.0","8.8.0","8.9.0","8.10.0","8.11.0","8.12.0","8.13.0","8.14.0","8.15.0","8.16.0","8.17.0","8.18.0","8.18.1","8.19.0","8.20.0","8.21.0"]}]},{"name":"unlock-premium","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"io.yuka.android","versions":[]}]},{"name":"unlock-prime","description":"Unlocks Nova Prime and all functions of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.teslacoilsw.launcher","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"co.windyapp.android","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all professional features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureVerificationPatch","LicenseValidationPatch"],"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364"]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.awedea.nyx","versions":[]}]},{"name":"unlock-themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ticktick.task","versions":[]}]},{"name":"unlock-trial","description":"Unlocks the trial version.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.dinglisch.android.taskerm","versions":[]}]},{"name":"upgrade-button-remover","description":"Removes the upgrade tab from the pivot bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"vanced-microg-support","description":"Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.","version":"0.0.1","excluded":false,"options":[],"dependencies":["microg-resource-patch","hide-cast-button"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"video-ads","description":"Removes ads in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]},{"name":"wide-searchbar","description":"Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37","18.03.36","18.03.42","18.04.35","18.04.41","18.05.32","18.05.35","18.05.40","18.08.37","18.15.40","18.16.37"]}]}] \ No newline at end of file +[{"name":"always-autorepeat","description":"Always repeats the playing video again.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"auto-claim-channel-points","description":"Automatically claim Channel Points.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"background-play","description":"Enables playing music in the background.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"block-audio-ads","description":"Blocks audio ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"block-embedded-ads","description":"Blocks embedded stream ads using services like TTV.lol or PurpleAdBlocker.","version":"0.0.1","excluded":false,"options":[],"dependencies":["block-video-ads","integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"block-video-ads","description":"Blocks video ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":["14.3.3","14.4.0","14.5.0","14.5.2","14.6.0","14.6.1"]}]},{"name":"bypass-certificate-checks","description":"Bypasses certificate checks which prevent YouTube Music from working on Android Auto.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52","5.40.51","5.41.50","5.48.52"]}]},{"name":"change-package-name","description":"Changes the package name.","version":"0.0.1","excluded":true,"options":[{"key":"packageName","title":"Package name","description":"The name of the package to rename of the app.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"client-spoof","description":"Spoofs a patched client to allow playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-signature-verification"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"codecs-unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"comments","description":"Hides components related to comments.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"compact-header","description":"Hides the music category bar at the top of the homepage.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"copy-video-url","description":"Adds buttons in player to copy video links.","version":"0.0.1","excluded":false,"options":[],"dependencies":["copy-video-url-resource","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"custom-branding","description":"Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).","version":"0.0.1","excluded":false,"options":[{"key":"appName","title":"Application Name","description":"The name of the application it will show on your home screen.","required":true,"choices":null},{"key":"iconPath","title":"App Icon Path","description":"A path containing mipmap resource folders with icons.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"custom-video-buffer","description":"Lets you change the buffers of videos.","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"debug-mode","description":"Enables Twitch\u0027s internal debugging mode.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"disable-ads","description":"Disables ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["DisablePiracyDetectionPatch"],"compatiblePackages":[{"name":"com.laurencedawson.reddit_sync","versions":[]}]},{"name":"disable-ads","description":"Disables ads in HexEditor.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.myprog.hexedit","versions":[]}]},{"name":"disable-auto-captions","description":"Disable forced captions from being automatically enabled.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-capture-restriction","description":"Allows capturing Spotify\u0027s audio output while screen sharing or screen recording.","version":"0.0.2","excluded":false,"options":[],"dependencies":["disable-capture-restriction-resource-patch"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"disable-fullscreen-panels","description":"Disables video description and comments panel in fullscreen view.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-login-requirement","description":"Do not force login.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"disable-player-popup-panels","description":"Disables panels from appearing automatically when going into fullscreen (playlist or live chat).","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-shorts-on-startup","description":"Disables playing YouTube Shorts when launching YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"disable-switching-emoji-to-sticker-in-message-input-field","description":"Disables switching from emoji to sticker search mode in message input field","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"disable-typing-indicator","description":"Disables the indicator while typing a message","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"disable-zoom-haptics","description":"Disables haptics when zooming.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"downloads","description":"Adds a download button to the YouTube video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["downloads-resource-patch","player-controls-bytecode-patch","video-information"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"downloads","description":"Removes download restrictions and changes the default path to download to.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"dynamic-color","description":"Replaces the default Twitter Blue with the users Material You palette.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"enable-android-debugging","description":"Enables Android debugging capabilities.","version":"0.0.1","excluded":true,"options":[{"key":"debuggable","title":"App debugging","description":"Whether to make the app debuggable on Android.","required":false,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"enable-debugging","description":"Adds debugging options.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings","enable-android-debugging"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"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.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.lite","versions":[]}]},{"name":"exclusive-audio-playback","description":"Enables the option to play music without video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"export-all-activities","description":"Makes all app activities exportable.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"feed-filter","description":"Filters tiktok videos: removing ads, removing livestreams.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"fix-google-login","description":"Allows logging in with a Google account.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hdr-auto-brightness","description":"Makes the brightness of HDR videos follow the system default.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-ads","description":"Removes general ads from the Reddit frontpage and subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideAdsResourcePatch","VerticalScrollPatch","FixBackToExitGesturePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-ads","description":"Removes ads from Inshorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.nis.app","versions":[]}]},{"name":"hide-ads","description":"Hides ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["VerticalScrollPatch"],"compatiblePackages":[{"name":"com.vanced.android.youtube","versions":[]}]},{"name":"hide-ads","description":"Removes ads from TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hide-album-cards","description":"Hides the album cards below the artist description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-album-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-artist-card","description":"Hides the artist card below the searchbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-autoplay-button","description":"Hides the autoplay button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-breaking-news-shelf","description":"Hides the breaking news shelf on the homepage tab.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","breaking-news-shelf-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-captions-button","description":"Hides the captions button on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-cast-button","description":"Hides the cast button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-crowdfunding-box","description":"Hides the crowdfunding box between the player and video description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","crowdfunding-box-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-email-address","description":"Hides the email address in the account switcher.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-email-address-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-endscreen-cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-endscreen-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-filter-bar","description":"Hides the filter bar in video feeds.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFilterBarResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-floating-microphone-button","description":"Hides the floating microphone button which appears in search.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideFloatingMicrophoneButtonResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-get-premium","description":"Hides advertisement for YouTube Premium under the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-get-premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51","5.38.53","5.39.52"]}]},{"name":"hide-inbox-ads","description":"Hides ads in inbox.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.facebook.orca","versions":[]}]},{"name":"hide-info-cards","description":"Hides info cards in videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","HideInfocardsResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-load-more-button","description":"Hides the button under videos that loads similar videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-load-more-button-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-player-buttons","description":"Adds the option to hide video player previous and next buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-player-overlay","description":"Hides the dark background overlay from the player when player controls are visible.","version":"0.0.2","excluded":false,"options":[],"dependencies":["HidePlayerOverlayResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-premium-navbar","description":"Removes the premium tab from the navbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"hide-recommended-users","description":"Hides recommended users.","version":"0.0.1","excluded":false,"options":[],"dependencies":["json-hook"],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"hide-seekbar","description":"Hides the seekbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","SeekbarColorBytecodePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-shorts-components","description":"Hides components from YouTube Shorts.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","LithoFilterPatch","HideShortsComponentsResourcePatch","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-subreddit-banner","description":"Hides banner ads from comments on subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"hide-timeline-ads","description":"Removes ads from the timeline.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.instagram.android","versions":[]}]},{"name":"hide-timestamp","description":"Hides timestamp in video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-video-action-buttons","description":"Adds the options to hide action buttons under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-views-stats","description":"Hides the view stats under tweets.","version":"0.0.1","excluded":false,"options":[],"dependencies":["HideViewsBytecodePatch"],"compatiblePackages":[{"name":"com.twitter.android","versions":["9.69.1-release.0","9.71.0-release.0"]}]},{"name":"hide-watch-in-vr","description":"Hides the option to watch in VR from the player settings flyout panel.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"hide-watermark","description":"Hides creator\u0027s watermarks on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"minimized-playback","description":"Enables minimized and background playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"minimized-playback-music","description":"Enables minimized playback on Kids music.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-microg-support","description":"Allows YouTube Music ReVanced to run without root and under a different package name.","version":"0.0.2","excluded":false,"options":[],"dependencies":["music-microg-resource-patch"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-video-ads","description":"Removes ads in the music player.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"navigation-buttons","description":"Adds options to hide or change navigation buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"old-quality-layout","description":"Enables the original video quality flyout in the video player settings.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","OldQualityLayoutResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"open-links-externally","description":"Open links outside of the app directly in your browser.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"playback-speed","description":"Enables the playback speed option for all videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"predictive-back-gesture","description":"Enables the predictive back gesture introduced on Android 13.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"premium-heading","description":"Shows premium branding on the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"premium-icon-reddit","description":"Unlocks premium Reddit app icons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"premium-unlock","description":"Unlocks premium functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.citra.citra_emu","versions":[]},{"name":"org.citra.citra_emu.canary","versions":[]}]},{"name":"pro-unlock","description":"Unlocks pro-only functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":["4.52"]}]},{"name":"promo-code-unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-cert-patch"],"compatiblePackages":[{"name":"de.dwd.warnapp","versions":[]}]},{"name":"remember-video-quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-information","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"remove-ads","description":"Removes all ads from the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.binarymode.android.irplus","versions":[]}]},{"name":"remove-bootloader-detection","description":"Removes the check for an unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":["2.2.0"]}]},{"name":"remove-broadcasts-restriction","description":"Enables starting/stopping NetGuard via broadcasts.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"eu.faircode.netguard","versions":[]}]},{"name":"remove-player-button-background","description":"Removes the background from the video player buttons.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions and unlocked bootloader.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"remove-root-detection","description":"Removes the check for root permissions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.bmf.bmf2go","versions":["2.2.0"]}]},{"name":"remove-screenshot-restriction","description":"Removes the restriction of taking screenshots in apps that normally wouldn\u0027t allow it.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"return-youtube-dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","return-youtube-dislike-resource-patch","player-type-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"sanitize-sharing-links","description":"Removes (tracking) query parameters from the URLs when sharing links.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","EnableSeekbarTappingResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"settings","description":"Adds settings menu to Twitch.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings-resource-patch"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"settings","description":"Adds ReVanced settings to TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"show-deleted-messages","description":"Shows deleted chat messages behind a clickable spoiler.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"show-seekbar","description":"Shows progress bar for all video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sim-spoof","description":"Spoofs the information which is retrieved from the sim-card.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":["27.8.3"]},{"name":"com.zhiliaoapp.musically","versions":["27.8.3"]}]},{"name":"sponsorblock","description":"Integrates SponsorBlock which allows skipping video segments such as sponsored content.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","video-information","player-type-hook","player-controls-bytecode-patch","sponsorblock-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"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.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"spoof-signature","description":"Spoofs the signature of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"at.gv.oe.app","versions":[]}]},{"name":"spoof-wifi-connection","description":"Spoofs an existing Wi-Fi connection.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"spotify-theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"backgroundColor","title":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentColor","title":"Accent color","description":"The accent color (\u0027spotify green\u0027 by default). Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentPressedColor","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,"choices":null}],"dependencies":[],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"swipe-controls","description":"Adds volume and brightness swipe controls.","version":"0.0.3","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","swipe-controls-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"tablet-mini-player","description":"Enables the tablet mini player layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"tasteBuilder-remover","description":"Removes the \"Tell us which artists you like\" card from the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"darkThemeBackgroundColor","title":"Background color for the dark theme","description":"The background color of the dark theme. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"lightThemeBackgroundColor","title":"Background color for the light theme","description":"The background color of the light theme. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"splashScreenBackgroundColor","title":"Background color for the splash screen","description":"The background color of the splash screen. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":["litho-color-hook","SeekbarColorBytecodePatch","ThemeResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"unlock-paid-widgets","description":"Unlocks paid widgets of the app","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.dci.dev.androidtwelvewidgets","versions":[]}]},{"name":"unlock-plus","description":"Unlocks plus features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureDetectionPatch"],"compatiblePackages":[{"name":"com.microblink.photomath","versions":["8.20.0"]}]},{"name":"unlock-premium","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"io.yuka.android","versions":[]}]},{"name":"unlock-prime","description":"Unlocks Nova Prime and all functions of the app.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.teslacoilsw.launcher","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.awedea.nyx","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"tv.trakt.trakt","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"co.windyapp.android","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["SignatureVerificationPatch","LicenseValidationPatch"],"compatiblePackages":[{"name":"com.zombodroid.MemeGenerator","versions":["4.6364","4.6370","4.6375","4.6377"]}]},{"name":"unlock-pro","description":"Unlocks premium features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.candylink.openvpn","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all professional features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":["3.4.9"]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.vsco.cam","versions":[]}]},{"name":"unlock-themes","description":"Unlocks all themes that are inaccessible until a certain level is reached.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ticktick.task","versions":[]}]},{"name":"unlock-trial","description":"Unlocks the trial version.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"net.dinglisch.android.taskerm","versions":[]}]},{"name":"upgrade-button-remover","description":"Removes the upgrade tab from the pivot bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"vanced-microg-support","description":"Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.","version":"0.0.1","excluded":false,"options":[],"dependencies":["microg-resource-patch","hide-cast-button","client-spoof"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"video-ads","description":"Removes ads in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"video-speed","description":"Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["custom-video-speed","remember-playback-speed"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]},{"name":"wide-searchbar","description":"Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["18.16.37","18.19.35"]}]}] \ 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 7c70f90c6..37b9ffcee 100644 --- a/src/main/kotlin/app/revanced/extensions/Extensions.kt +++ b/src/main/kotlin/app/revanced/extensions/Extensions.kt @@ -1,11 +1,15 @@ package app.revanced.extensions import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction import org.jf.dexlib2.util.MethodUtil import org.w3c.dom.Node @@ -15,7 +19,7 @@ import org.w3c.dom.Node * * @return A [PatchResultError] for the [MethodFingerprint]. */ -fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $name") +internal fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $name") /** * Find the [MutableMethod] from a given [Method] in a [MutableClass]. @@ -23,7 +27,7 @@ fun MethodFingerprint.toErrorResult() = PatchResultError("Failed to resolve $nam * @param method The [Method] to find. * @return The [MutableMethod]. */ -fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { +internal fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { MethodUtil.methodSignaturesMatch(it, method) } @@ -32,7 +36,7 @@ fun MutableClass.findMutableMethodOf(method: Method) = this.methods.first { * * @param transform the transformation function. original method goes in, transformed method goes out */ -fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) { +internal fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) { val transformedMethods = methods.map { it.transform() } methods.clear() methods.addAll(transformedMethods) @@ -41,4 +45,29 @@ fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) internal fun Node.doRecursively(action: (Node) -> Unit) { action(this) for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action) +} + +internal fun MutableMethod.injectHideViewCall( + insertIndex: Int, + viewRegister: Int, + classDescriptor: String, + targetMethod: String +) = addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $classDescriptor->$targetMethod(Landroid/view/View;)V" +) + +internal fun MutableMethod.findIndexForIdResource(resourceName: String): Int { + fun getIdResourceId(resourceName: String) = ResourceMappingPatch.resourceMappings.single { + it.type == "id" && it.name == resourceName + }.id + + val resourceId = getIdResourceId(resourceName) + return implementation!!.instructions.indexOfFirst { + if (it.opcode != Opcode.CONST) return@indexOfFirst false + + val literal = (it as WideLiteralInstruction).wideLiteral + + return@indexOfFirst resourceId == literal + } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt b/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt index 530ca0500..e8a951eac 100644 --- a/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt +++ b/src/main/kotlin/app/revanced/meta/ReadmeGenerator.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.PatchExtensions.compatiblePackages import app.revanced.patcher.extensions.PatchExtensions.description import app.revanced.patcher.extensions.PatchExtensions.patchName import app.revanced.patcher.patch.Patch +import com.unascribed.flexver.FlexVerComparator import java.io.File internal class ReadmeGenerator : PatchesFileGenerator { @@ -37,9 +38,8 @@ internal class ReadmeGenerator : PatchesFileGenerator { } }.let { commonMap -> commonMap.maxByOrNull { it.value }?.value?.let { - // This is not foolproof, because for example v1.0.0-dev.0 will be returned instead of v1.0.0-release. - // Unfortunately this can not be solved easily because versioning can be complex. - commonMap.entries.filter { mostCommon -> mostCommon.value == it }.maxBy { it.key }.key + commonMap.entries.filter { mostCommon -> mostCommon.value == it } + .maxOfWith(FlexVerComparator::compare, Map.Entry<String, Int>::key) } ?: "all" } diff --git a/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt b/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt index 20a754759..de1f10d06 100644 --- a/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt +++ b/src/main/kotlin/app/revanced/patches/all/misc/packagename/patch/ChangePackageNamePatch.kt @@ -19,7 +19,7 @@ class ChangePackageNamePatch : ResourcePatch { if (!packageName.matches(packageNameRegex)) return PatchResultError("Invalid package name") - var originalPackageName = "" + var originalPackageName: String context.xmlEditor["AndroidManifest.xml"].use { editor -> val manifest = editor.file.getElementsByTagName("manifest").item(0) as Element originalPackageName = manifest.getAttribute("package") diff --git a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt index 7deff0a9c..2835fc0b2 100644 --- a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt @@ -11,5 +11,8 @@ object ProUnlockFingerprint : MethodFingerprint( Opcode.MOVE_RESULT, Opcode.IF_EQZ ), - customFingerprint = { it.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;" && it.name == "lambda\$existPurchase\$0" } + customFingerprint = { methodDef, _ -> + methodDef.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;" + && methodDef.name == "lambda\$existPurchase\$0" + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt index 0365284d8..94f41526c 100644 --- a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt +++ b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt @@ -1,15 +1,14 @@ package app.revanced.patches.backdrops.misc.pro.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.MethodFingerprintExtensions.name import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.instruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.backdrops.misc.pro.annotations.ProUnlockCompatibility @@ -25,17 +24,20 @@ class ProUnlockPatch : BytecodePatch( listOf(ProUnlockFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - val result = ProUnlockFingerprint.result ?: return PatchResultError("${ProUnlockFingerprint.name} not found") + ProUnlockFingerprint.result?.let { result -> + val registerIndex = result.scanResult.patternScanResult!!.endIndex - 1 - val moveRegisterInstruction = result.mutableMethod.instruction(result.scanResult.patternScanResult!!.endIndex - 1) - val register = (moveRegisterInstruction as OneRegisterInstruction).registerA + result.mutableMethod.apply { + val register = instruction<OneRegisterInstruction>(registerIndex).registerA + addInstructions( + result.scanResult.patternScanResult!!.endIndex, + """ + const/4 v$register, 0x1 + """ + ) + } - result.mutableMethod.addInstructions( - result.scanResult.patternScanResult!!.endIndex, - """ - const/4 v$register, 0x1 - """ - ) + } ?: return ProUnlockFingerprint.toErrorResult() return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/candylinkvpn/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/candylinkvpn/annotations/UnlockProCompatibility.kt new file mode 100644 index 000000000..36c0f653c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/candylinkvpn/annotations/UnlockProCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.candylinkvpn.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.candylink.openvpn")]) +@Target(AnnotationTarget.CLASS) +internal annotation class UnlockProCompatibility diff --git a/src/main/kotlin/app/revanced/patches/candylinkvpn/fingereprints/IsPremiumPurchasedFingerprint.kt b/src/main/kotlin/app/revanced/patches/candylinkvpn/fingereprints/IsPremiumPurchasedFingerprint.kt new file mode 100644 index 000000000..394b3c1f4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/candylinkvpn/fingereprints/IsPremiumPurchasedFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.candylinkvpn.fingereprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object IsPremiumPurchasedFingerprint : MethodFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("PreferenceProvider;") && + methodDef.name == "isPremiumPurchased" + } +) { +} diff --git a/src/main/kotlin/app/revanced/patches/candylinkvpn/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/candylinkvpn/patch/UnlockProPatch.kt new file mode 100644 index 000000000..9905df4de --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/candylinkvpn/patch/UnlockProPatch.kt @@ -0,0 +1,37 @@ +package app.revanced.patches.candylinkvpn.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.candylinkvpn.annotations.UnlockProCompatibility +import app.revanced.patches.candylinkvpn.fingereprints.IsPremiumPurchasedFingerprint + +@Patch +@Name("unlock-pro") +@Description("Unlocks premium features.") +@UnlockProCompatibility +@Version("0.0.1") +class UnlockProPatch : BytecodePatch( + listOf(IsPremiumPurchasedFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + IsPremiumPurchasedFingerprint.result?.let { + it.mutableMethod.addInstructions( + 0, + """ + const/4 v0, 0x1 + return v0 + """ + ) + } ?: return IsPremiumPurchasedFingerprint.toErrorResult() + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt index 347c31a2d..736664734 100644 --- a/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt @@ -3,5 +3,7 @@ package app.revanced.patches.citra.misc.premium.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PremiumUnlockFingerprint : MethodFingerprint( - customFingerprint = { it.definingClass == "Lorg/citra/citra_emu/ui/main/MainActivity;" && it.name == "isPremiumActive" } + customFingerprint = { methodDef, _ -> + methodDef.definingClass == "Lorg/citra/citra_emu/ui/main/MainActivity;" && methodDef.name == "isPremiumActive" + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootStateFingerprint.kt b/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootStateFingerprint.kt index 766147aca..f6aff1191 100644 --- a/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootStateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootStateFingerprint.kt @@ -5,9 +5,9 @@ import org.jf.dexlib2.AccessFlags object BootStateFingerprint : MethodFingerprint( "Z", - access = AccessFlags.PUBLIC.value, + accessFlags = AccessFlags.PUBLIC.value, strings = listOf("Boot state of device: %s"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/AttestationHelper;") } ) diff --git a/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootloaderDetectionFingerprint.kt b/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootloaderDetectionFingerprint.kt index 2d24a6ccc..9bfe0ba21 100644 --- a/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootloaderDetectionFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/finanzonline/detection/bootloader/fingerprints/BootloaderDetectionFingerprint.kt @@ -5,9 +5,9 @@ import org.jf.dexlib2.AccessFlags object BootloaderDetectionFingerprint : MethodFingerprint( "Z", - access = AccessFlags.PUBLIC.value, + accessFlags = AccessFlags.PUBLIC.value, strings = listOf("Creation of attestation key succeeded", "Creation of attestation key failed"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/AttestationHelper;") } ) diff --git a/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/fingerprints/RootDetectionFingerprint.kt b/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/fingerprints/RootDetectionFingerprint.kt index b2e793da4..3c3617dcd 100644 --- a/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/fingerprints/RootDetectionFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/finanzonline/detection/root/fingerprints/RootDetectionFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object RootDetectionFingerprint : MethodFingerprint( "L", - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lat/gv/bmf/bmf2go/tools/utils/z;" } ) diff --git a/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt index 34c3e94af..ada038515 100644 --- a/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.hexeditor.ad.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PrimaryAdsFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("PreferencesHelper;") && methodDef.name == "isAdsDisabled" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt b/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt index 945ef2ca9..8ecdb5032 100644 --- a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt @@ -4,5 +4,5 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object CheckProFingerprint : MethodFingerprint( "Z", - customFingerprint = { it.definingClass.endsWith("IPSPurchaseRepository;")} + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("IPSPurchaseRepository;")} ) diff --git a/src/main/kotlin/app/revanced/patches/idaustria/detection/root/fingerprints/RootDetectionFingerprint.kt b/src/main/kotlin/app/revanced/patches/idaustria/detection/root/fingerprints/RootDetectionFingerprint.kt index a64808a5f..185a9e5ad 100644 --- a/src/main/kotlin/app/revanced/patches/idaustria/detection/root/fingerprints/RootDetectionFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/idaustria/detection/root/fingerprints/RootDetectionFingerprint.kt @@ -5,8 +5,8 @@ import org.jf.dexlib2.AccessFlags object RootDetectionFingerprint : MethodFingerprint( "V", - access = AccessFlags.PUBLIC.value, - customFingerprint = { methodDef -> + accessFlags = AccessFlags.PUBLIC.value, + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/DeviceIntegrityCheck;") } ) diff --git a/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/fingerprints/SpoofSignatureFingerprint.kt b/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/fingerprints/SpoofSignatureFingerprint.kt index 34aa826a3..c11b2e0b6 100644 --- a/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/fingerprints/SpoofSignatureFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/idaustria/detection/signature/fingerprints/SpoofSignatureFingerprint.kt @@ -6,8 +6,8 @@ import org.jf.dexlib2.AccessFlags object SpoofSignatureFingerprint : MethodFingerprint( "L", parameters = listOf("L"), - access = AccessFlags.PRIVATE.value, - customFingerprint = { methodDef -> + accessFlags = AccessFlags.PRIVATE.value, + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/SL2Step1Task;") && methodDef.name == "getPubKey" } ) diff --git a/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt index 1cbb57933..0aba22b1b 100644 --- a/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/inshorts/ad/fingerprints/InshortsAdsFingerprint.kt @@ -1,9 +1,8 @@ package app.revanced.patches.inshorts.ad.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode object InshortsAdsFingerprint : MethodFingerprint( "V", - strings = listOf("GoogleAdLoader","exception in requestAd") + strings = listOf("GoogleAdLoader","exception in requestAd"), ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/MediaAdFingerprint.kt b/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/MediaAdFingerprint.kt index d505347af..b31290f70 100644 --- a/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/MediaAdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/MediaAdFingerprint.kt @@ -4,17 +4,18 @@ import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.Method abstract class MediaAdFingerprint( returnType: String? = "Z", - access: Int? = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags: Int? = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters: Iterable<String>? = listOf(), opcodes: Iterable<Opcode>?, - customFingerprint: ((methodDef: Method) -> Boolean)? = null + customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null ) : MethodFingerprint( returnType, - access, + accessFlags, parameters, opcodes, customFingerprint = customFingerprint diff --git a/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/PaidPartnershipAdFingerprint.kt b/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/PaidPartnershipAdFingerprint.kt index 0dfa62a77..0f10168c6 100644 --- a/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/PaidPartnershipAdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/fingerprints/ads/PaidPartnershipAdFingerprint.kt @@ -14,7 +14,7 @@ object PaidPartnershipAdFingerprint : MediaAdFingerprint( Opcode.IPUT_BOOLEAN, Opcode.IPUT_BOOLEAN ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("ClipsEditMetadataController;") } ) { diff --git a/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/patch/HideTimelineAdsPatch.kt b/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/patch/HideTimelineAdsPatch.kt index 5eb220cfc..6ba2dd958 100644 --- a/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/patch/HideTimelineAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/instagram/patches/ads/timeline/patch/HideTimelineAdsPatch.kt @@ -55,8 +55,8 @@ class HideTimelineAdsPatch : BytecodePatch( val scanStart = scanResult.patternScanResult!!.startIndex val jumpIndex = scanStart - 1 - val mediaInstanceRegister = (mutableMethod.instruction(scanStart) as FiveRegisterInstruction).registerC - val freeRegister = (mutableMethod.instruction(jumpIndex) as OneRegisterInstruction).registerA + val mediaInstanceRegister = mutableMethod.instruction<FiveRegisterInstruction>(scanStart).registerC + val freeRegister = mutableMethod.instruction<OneRegisterInstruction>(jumpIndex).registerA val returnFalseLabel = "an_ad" diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt b/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt index 205bca30a..9de66ac2a 100644 --- a/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/memegenerator/detection/license/fingerprint/LicenseValidationFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object LicenseValidationFingerprint : MethodFingerprint( returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.STATIC, + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("Landroid/content/Context;"), opcodes = listOf( Opcode.INVOKE_STATIC, diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt b/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt index 7c0304ebb..bc8cdc9fb 100644 --- a/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/memegenerator/detection/signature/fingerprint/VerifySignatureFingerprint.kt @@ -9,7 +9,7 @@ import org.jf.dexlib2.Opcode @FuzzyPatternScanMethod(2) object VerifySignatureFingerprint : MethodFingerprint( returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.STATIC, + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, parameters = listOf("Landroid/app/Activity;"), opcodes = listOf( Opcode.SGET_OBJECT, diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt index bf92bccaa..b93215674 100644 --- a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/annotations/UnlockProCompatibility.kt @@ -3,6 +3,15 @@ package app.revanced.patches.memegenerator.misc.pro.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility([Package("com.zombodroid.MemeGenerator", arrayOf("4.6364"))]) +@Compatibility( + [Package( + "com.zombodroid.MemeGenerator", arrayOf( + "4.6364", + "4.6370", + "4.6375", + "4.6377", + ) + )] +) @Target(AnnotationTarget.CLASS) internal annotation class UnlockProCompatibility diff --git a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt index be9b266ba..19f08da0e 100644 --- a/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/memegenerator/misc/pro/fingerprint/IsFreeVersionFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object IsFreeVersionFingerprint : MethodFingerprint( returnType = "Ljava/lang/Boolean;", - access = AccessFlags.PUBLIC or AccessFlags.STATIC, + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, strings = listOf("free"), parameters = listOf("Landroid/content/Context;"), opcodes = listOf( diff --git a/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt index c29b94448..3bb5c3a38 100644 --- a/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/messenger/ads/inbox/fingerprints/LoadInboxAdsFingerprint.kt @@ -10,9 +10,9 @@ object LoadInboxAdsFingerprint : MethodFingerprint( "ads_load_begin", "inbox_ads_fetch_start" ), - access = AccessFlags.PUBLIC or AccessFlags.STATIC, - customFingerprint = { - it.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;" + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + customFingerprint = { methodDef, _ -> + methodDef.definingClass == "Lcom/facebook/messaging/business/inboxads/plugins/inboxads/itemsupplier/InboxAdsItemSupplierImplementation;" } ) diff --git a/src/main/kotlin/app/revanced/patches/messenger/inputfield/fingerprints/SendTypingIndicatorFingerprint.kt b/src/main/kotlin/app/revanced/patches/messenger/inputfield/fingerprints/SendTypingIndicatorFingerprint.kt new file mode 100644 index 000000000..cff25ae29 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/messenger/inputfield/fingerprints/SendTypingIndicatorFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.messenger.inputfield.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.dexbacked.value.DexBackedStringEncodedValue + +object SendTypingIndicatorFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf(), + customFingerprint = { methodDef, classDef -> + methodDef.name == "run" && classDef.fields.any { + it.name == "__redex_internal_original_name" + && (it.initialValue as? DexBackedStringEncodedValue)?.value == "ConversationTypingContext\$sendActiveStateRunnable\$1" + } + } +) diff --git a/src/main/kotlin/app/revanced/patches/messenger/inputfield/fingerprints/SwitchMessangeInputEmojiButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/messenger/inputfield/fingerprints/SwitchMessangeInputEmojiButtonFingerprint.kt new file mode 100644 index 000000000..ef01e1a5a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/messenger/inputfield/fingerprints/SwitchMessangeInputEmojiButtonFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.messenger.inputfield.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object SwitchMessangeInputEmojiButtonFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L", "Z"), + strings = listOf("afterTextChanged", "expression_search"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.IF_EQZ, + Opcode.CONST_STRING, + Opcode.GOTO, + Opcode.CONST_STRING, + Opcode.GOTO + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/messenger/inputfield/patch/DisableSwitchingEmojiToStickerInMessageInputField.kt b/src/main/kotlin/app/revanced/patches/messenger/inputfield/patch/DisableSwitchingEmojiToStickerInMessageInputField.kt new file mode 100644 index 000000000..3d577a339 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/messenger/inputfield/patch/DisableSwitchingEmojiToStickerInMessageInputField.kt @@ -0,0 +1,37 @@ +package app.revanced.patches.messenger.inputfield.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.* +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.messenger.inputfield.fingerprints.SwitchMessangeInputEmojiButtonFingerprint +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Patch +@Name("disable-switching-emoji-to-sticker-in-message-input-field") +@Description("Disables switching from emoji to sticker search mode in message input field") +@Compatibility([Package("com.facebook.orca")]) +@Version("0.0.1") +class DisableSwitchingEmojiToStickerInMessageInputField : BytecodePatch(listOf(SwitchMessangeInputEmojiButtonFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + SwitchMessangeInputEmojiButtonFingerprint.result?.let { + val setStringIndex = it.scanResult.patternScanResult!!.startIndex + 2 + + it.mutableMethod.apply { + val targetRegister = instruction<OneRegisterInstruction>(setStringIndex).registerA + + replaceInstruction( + setStringIndex, + "const-string v$targetRegister, \"expression\"" + ) + } + } ?: throw SwitchMessangeInputEmojiButtonFingerprint.toErrorResult() + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/messenger/inputfield/patch/DisableTypingIndicator.kt b/src/main/kotlin/app/revanced/patches/messenger/inputfield/patch/DisableTypingIndicator.kt new file mode 100644 index 000000000..d25d46ed9 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/messenger/inputfield/patch/DisableTypingIndicator.kt @@ -0,0 +1,29 @@ +package app.revanced.patches.messenger.inputfield.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Package +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.messenger.inputfield.fingerprints.SendTypingIndicatorFingerprint + +@Patch +@Name("disable-typing-indicator") +@Description("Disables the indicator while typing a message") +@Compatibility([Package("com.facebook.orca")]) +@Version("0.0.1") +class DisableTypingIndicator : BytecodePatch(listOf(SendTypingIndicatorFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + SendTypingIndicatorFingerprint.result?.mutableMethod?.replaceInstruction(0, "return-void") + ?: throw SendTypingIndicatorFingerprint.toErrorResult() + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt b/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt index 9ea14f8ac..c7b6824a1 100644 --- a/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt @@ -13,7 +13,7 @@ object UnlockProFingerprint : MethodFingerprint( Opcode.IGET_BOOLEAN, Opcode.RETURN ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("MainActivity;") } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt index 90b0af58d..d03ed1527 100644 --- a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.nyx.misc.pro.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object CheckProFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("BillingManager;") && methodDef.name == "isProVersion" } ) diff --git a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt index 2f460c694..df2445be7 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/detection/signature/fingerprints/CheckSignatureFingerprint.kt @@ -7,11 +7,11 @@ import org.jf.dexlib2.Opcode object CheckSignatureFingerprint : MethodFingerprint( returnType = "V", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { - (it.definingClass == "Lcom/microblink/photomath/main/activity/LauncherActivity;" || - it.definingClass == "Lcom/microblink/photomath/PhotoMath;") && - it.name == "onCreate" + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + customFingerprint = { methodDef, _ -> + (methodDef.definingClass == "Lcom/microblink/photomath/main/activity/LauncherActivity;" || + methodDef.definingClass == "Lcom/microblink/photomath/PhotoMath;") && + methodDef.name == "onCreate" }, strings = listOf( "currentSignature" diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt index 29f8379df..aa73c1fd3 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/annotations/UnlockPlusCompatibilty.kt @@ -3,28 +3,6 @@ package app.revanced.patches.photomath.misc.unlockplus.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.microblink.photomath", arrayOf( - "8.6.0", - "8.7.0", - "8.8.0", - "8.9.0", - "8.10.0", - "8.11.0", - "8.12.0", - "8.13.0", - "8.14.0", - "8.15.0", - "8.16.0", - "8.17.0", - "8.18.0", - "8.18.1", - "8.19.0", - "8.20.0", - "8.21.0", - ) - )] -) +@Compatibility([Package("com.microblink.photomath", arrayOf("8.20.0"))]) @Target(AnnotationTarget.CLASS) internal annotation class UnlockPlusCompatibilty diff --git a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt b/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt index eb2f74644..9f9dddffa 100644 --- a/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/photomath/misc/unlockplus/fingerprints/IsPlusUnlockedFingerprint.kt @@ -6,11 +6,11 @@ import org.jf.dexlib2.AccessFlags object IsPlusUnlockedFingerprint : MethodFingerprint( returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, strings = listOf( "genius" ), customFingerprint = { - methodDef -> methodDef.definingClass.endsWith("/User;") + methodDef, _ -> methodDef.definingClass.endsWith("/User;") } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt index ffac6ed55..90daa6b62 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/ad/banner/annotations/HideBannerCompatibility.kt @@ -5,18 +5,7 @@ import app.revanced.patcher.annotation.Package @Compatibility( [Package( - "com.reddit.frontpage", arrayOf( - "2023.05.0", - "2023.06.0", - "2023.07.0", - "2023.07.1", - "2023.08.0", - "2023.09.0", - "2023.09.1", - "2023.10.0", - "2023.11.0", - "2023.12.0" - ) + "com.reddit.frontpage" )] ) @Target(AnnotationTarget.CLASS) diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt deleted file mode 100644 index e513e941e..000000000 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.patches.reddit.ad.general.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.reddit.frontpage", arrayOf( - "2021.45.0", - "2022.43.0", - "2023.05.0", - "2023.06.0", - "2023.07.0", - "2023.07.1", - "2023.08.0", - "2023.09.0", - "2023.09.1", - "2023.10.0", - "2023.11.0", - "2023.12.0" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class GeneralAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/HideAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/HideAdsCompatibility.kt new file mode 100644 index 000000000..f8dbd2d66 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/HideAdsCompatibility.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.reddit.ad.general.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.reddit.frontpage" + )] +) +@Target(AnnotationTarget.CLASS) +internal annotation class HideAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/GeneralAdsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/HideAdsPatch.kt similarity index 92% rename from src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/GeneralAdsPatch.kt rename to src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/HideAdsPatch.kt index 86341a62a..7f58d558e 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/GeneralAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/HideAdsPatch.kt @@ -8,7 +8,7 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.reddit.ad.general.annotations.GeneralAdsCompatibility +import app.revanced.patches.reddit.ad.general.annotations.HideAdsCompatibility import org.jf.dexlib2.Opcode import org.jf.dexlib2.builder.instruction.BuilderInstruction21c import org.jf.dexlib2.iface.instruction.ReferenceInstruction @@ -16,11 +16,11 @@ import org.jf.dexlib2.iface.reference.StringReference import org.jf.dexlib2.immutable.reference.ImmutableStringReference @Patch -@Name("general-reddit-ads") +@Name("hide-ads") @Description("Removes general ads from the Reddit frontpage and subreddits.") -@GeneralAdsCompatibility +@HideAdsCompatibility @Version("0.0.1") -class GeneralAdsPatch : BytecodePatch() { +class HideAdsPatch : BytecodePatch() { override fun execute(context: BytecodeContext): PatchResult { context.classes.forEach { classDef -> classDef.methods.forEach methodLoop@{ method -> diff --git a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt index bb8bf0d35..c406791ed 100644 --- a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PremiumIconFingerprint : MethodFingerprint( "Z", - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("MyAccount;") && methodDef.name == "isPremiumSubscriber" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/annotations/SanitizeUrlQueryCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/annotations/SanitizeUrlQueryCompatibility.kt new file mode 100644 index 000000000..6ba4a8902 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/annotations/SanitizeUrlQueryCompatibility.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.reddit.misc.tracking.url.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility( + [Package( + "com.reddit.frontpage" + )] +) +@Target(AnnotationTarget.CLASS) +internal annotation class SanitizeUrlQueryCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/fingerprints/ShareLinkFactoryFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/fingerprints/ShareLinkFactoryFingerprint.kt new file mode 100644 index 000000000..e3ec8ff90 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/fingerprints/ShareLinkFactoryFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.reddit.misc.tracking.url.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ShareLinkFactoryFingerprint : MethodFingerprint( + returnType = "L", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + opcodes = listOf( + Opcode.CONST_STRING, + Opcode.CONST_STRING, + Opcode.INVOKE_DIRECT, + Opcode.APUT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, // Returns the URL. + Opcode.MOVE_RESULT_OBJECT + ), + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("ShareLinkFactory;") } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/patch/SanitizeUrlQueryPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/patch/SanitizeUrlQueryPatch.kt new file mode 100644 index 000000000..1f494a401 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/reddit/misc/tracking/url/patch/SanitizeUrlQueryPatch.kt @@ -0,0 +1,52 @@ +package app.revanced.patches.reddit.misc.tracking.url.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.annotations.RequiresIntegrations +import app.revanced.patches.reddit.misc.tracking.url.annotations.SanitizeUrlQueryCompatibility +import app.revanced.patches.reddit.misc.tracking.url.fingerprints.ShareLinkFactoryFingerprint +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Patch +@Name("sanitize-sharing-links") +@Description("Removes (tracking) query parameters from the URLs when sharing links.") +@SanitizeUrlQueryCompatibility +@Version("0.0.1") +@RequiresIntegrations +class SanitizeUrlQueryPatch : BytecodePatch( + listOf(ShareLinkFactoryFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + ShareLinkFactoryFingerprint.result?.let { result -> + result.mutableMethod.apply { + val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1 + val urlRegister = instruction<OneRegisterInstruction>(insertIndex - 1).registerA + + addInstructions( + insertIndex, + """ + invoke-static {v$urlRegister}, $SANITIZE_METHOD_DESCRIPTOR + move-result-object v$urlRegister + """ + ) + } + } ?: return ShareLinkFactoryFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + private companion object { + private const val SANITIZE_METHOD_DESCRIPTOR = + "Lapp/revanced/reddit/patches/SanitizeUrlQueryPatch;" + + "->stripQueryParameters(Ljava/lang/String;)Ljava/lang/String;" + } +} diff --git a/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt index 7afcdae85..8ec4e2567 100644 --- a/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt @@ -4,5 +4,5 @@ package app.revanced.patches.shared.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SeekbarOnDrawFingerprint : MethodFingerprint( - customFingerprint = { it.name == "onDraw" } + customFingerprint = { methodDef, _ -> methodDef.name == "onDraw" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt index b10c5e23e..eefe790f0 100644 --- a/src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.shared.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object WatchWhileActivityFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("WatchWhileActivity;") && methodDef.name == "<init>" } ) diff --git a/src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt index 2ef2e48dc..efa8d35be 100644 --- a/src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt @@ -9,6 +9,9 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint.RegisterResolver +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.ClassDef import org.jf.dexlib2.iface.Method @Description("Applies mandatory patches to implement the ReVanced integrations into the application.") @@ -24,10 +27,21 @@ abstract class AbstractIntegrationsPatch( * @see MethodFingerprint */ abstract class IntegrationsFingerprint( + returnType: String? = null, + accessFlags: Int? = null, + parameters: Iterable<String>? = null, + opcodes: Iterable<Opcode?>? = null, strings: Iterable<String>? = null, - customFingerprint: ((methodDef: Method) -> Boolean)? = null, + customFingerprint: ((methodDef: Method, classDef: ClassDef) -> Boolean)? = null, private val contextRegisterResolver: (Method) -> Int = object : RegisterResolver {} - ) : MethodFingerprint(strings = strings, customFingerprint = customFingerprint) { + ) : MethodFingerprint( + returnType, + accessFlags, + parameters, + opcodes, + strings, + customFingerprint + ) { fun invoke(integrationsDescriptor: String): PatchResult { result?.mutableMethod?.let { method -> val contextRegister = contextRegisterResolver(method) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/annotations/ClientSpoofCompatibility.kt b/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/annotations/ClientSpoofCompatibility.kt deleted file mode 100644 index dc3138144..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/annotations/ClientSpoofCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.shared.misc.fix.spoof.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class ClientSpoofCompatibility diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt index e5d137ca6..3301d2b34 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt @@ -13,5 +13,5 @@ object CanScrollVerticallyFingerprint : MethodFingerprint( Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT, ), - customFingerprint = { methodDef -> methodDef.definingClass.endsWith("SwipeRefreshLayout;") } + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("SwipeRefreshLayout;") } ) diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt b/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt index 557ccb5a3..e251f1dec 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt @@ -13,26 +13,25 @@ import app.revanced.patches.shared.misc.fix.verticalscroll.annotations.VerticalS import app.revanced.patches.shared.misc.fix.verticalscroll.fingerprints.CanScrollVerticallyFingerprint import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -@Description("Fixes issues with scrolling on the home screen when the first component is of type EmptyComponent.") +@Description("Fixes issues with refreshing the feed when the first component is of type EmptyComponent.") @VerticalScrollCompatibility @Version("0.0.1") class VerticalScrollPatch : BytecodePatch( listOf(CanScrollVerticallyFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - val result = CanScrollVerticallyFingerprint.result ?: return CanScrollVerticallyFingerprint.toErrorResult() + CanScrollVerticallyFingerprint.result?.let { + it.mutableMethod.apply { + val moveResultIndex = it.scanResult.patternScanResult!!.endIndex + val moveResultRegister = instruction<OneRegisterInstruction>(moveResultIndex).registerA - with(result) { - val method = mutableMethod - - val moveResultIndex = scanResult.patternScanResult!!.endIndex - val moveResultRegister = (method.instruction(moveResultIndex) as OneRegisterInstruction).registerA - - method.addInstruction( - moveResultIndex + 1, - "const/4 v$moveResultRegister, 0x0" - ) - } + val insertIndex = moveResultIndex + 1 + addInstruction( + insertIndex, + "const/4 v$moveResultRegister, 0x0" + ) + } + } ?: return CanScrollVerticallyFingerprint.toErrorResult() return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt index 1853a97c6..09fe4bc61 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt @@ -9,23 +9,26 @@ import org.w3c.dom.Element * * @param key The key of the preference. * @param title The title of the preference. + * @param tag The tag of the preference. + * @param summary The summary of the preference. */ internal abstract class BasePreference( - override val key: String, - override val title: StringResource, -) : IPreference { - + val key: String?, + val title: StringResource, + val summary: StringResource? = null, + val tag: String +) { /** * Serialize preference element to XML. * Overriding methods should invoke super and operate on its return value. * @param ownerDocument Target document to create elements from. * @param resourceCallback Called when a resource has been processed. + * @return The serialized element. */ - open fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)? = null): Element { - return ownerDocument.createElement(tag).apply { - if(key.isNotEmpty()) - setAttribute("android:key", key) - setAttribute("android:title", "@string/${title.also { resourceCallback?.invoke(it) }.name}") + open fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element = + ownerDocument.createElement(tag).apply { + if (key != null) setAttribute("android:key", key) + setAttribute("android:title", "@string/${title.also { resourceCallback.invoke(it) }.name}") + addSummary(summary?.also { resourceCallback.invoke(it) }) } - } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt index 5c5e4174b..61a9b35a2 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt @@ -7,18 +7,19 @@ import org.w3c.dom.Element * Base resource class for all resources. * * @param name The name of the resource. + * @param tag The tag of the resource. */ internal abstract class BaseResource( - override val name: String -) : IResource { - + val name: String, + val tag: String +) { /** * Serialize resource element to XML. * Overriding methods should invoke super and operate on its return value. * @param ownerDocument Target document to create elements from. * @param resourceCallback Called when a resource has been processed. */ - open fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)? = null): Element { + open fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit = { }): Element { return ownerDocument.createElement(tag).apply { setAttribute("name", name) } diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt index b0e8ddbd6..21207188b 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt @@ -10,7 +10,7 @@ import org.w3c.dom.Node * @param resource The resource to add. * @param resourceCallback Called when a resource has been processed. */ -internal fun Node.addResource(resource: BaseResource, resourceCallback: ((IResource) -> Unit)? = null) { +internal fun Node.addResource(resource: BaseResource, resourceCallback: (BaseResource) -> Unit = { }) { appendChild(resource.serialize(ownerDocument, resourceCallback)) } @@ -20,7 +20,7 @@ internal fun Node.addResource(resource: BaseResource, resourceCallback: ((IResou * @param preference The preference to add. * @param resourceCallback Called when a resource has been processed. */ -internal fun Node.addPreference(preference: BasePreference, resourceCallback: ((IResource) -> Unit)? = null) { +internal fun Node.addPreference(preference: BasePreference, resourceCallback: ((BaseResource) -> Unit) = { }) { appendChild(preference.serialize(ownerDocument, resourceCallback)) } @@ -30,10 +30,11 @@ internal fun Element.addSummary(summaryResource: StringResource?, summaryType: S } internal fun <T> Element.addDefault(default: T) { + if (default is Boolean && !(default as Boolean)) return // No need to include the default, as no value already means 'false' default?.let { setAttribute( "android:defaultValue", when (it) { - is Boolean -> if (it) "true" else "false" + is Boolean -> it.toString() is String -> it else -> throw IllegalArgumentException("Unsupported default value type: ${it::class.java.name}") } diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/DefaultBasePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/DefaultBasePreference.kt new file mode 100644 index 000000000..64d35878c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/DefaultBasePreference.kt @@ -0,0 +1,32 @@ +package app.revanced.patches.shared.settings.preference + +import app.revanced.patches.shared.settings.preference.impl.StringResource +import org.w3c.dom.Document + +/** + * Base preference class that also has a default value. + * + * @param key The key of the preference. + * @param title The title of the preference. + * @param tag The tag of the preference. + * @param summary The summary of the preference. + * @param default The default value of the preference. + */ +internal abstract class DefaultBasePreference<T>( + key: String?, + title: StringResource, + summary: StringResource? = null, + tag: String, + val default: T? = null, +) : BasePreference(key, title, summary, tag) { + + /** + * Serialize preference element to XML. + * Overriding methods should invoke super and operate on its return value. + * @param ownerDocument Target document to create elements from. + * @param resourceCallback Called when a resource has been processed. + * @return The serialized element. + */ + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { addDefault(default) } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/IPreference.kt deleted file mode 100644 index ec31835ba..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IPreference.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource - -/** - * Preference - */ -internal interface IPreference { - /** - * Key of the preference. - */ - val key: String - - /** - * Title of the preference. - */ - val title: StringResource - - /** - * Tag name of the preference. - */ - val tag: String -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/IResource.kt deleted file mode 100644 index dc3fe610e..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IResource.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -/** - * Resource - */ -internal interface IResource { - /** - * Name of the resource. - */ - val name: String - - /** - * Tag name of the resource. - */ - val tag: String -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt index 90795e1f7..9db57cff0 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt @@ -1,34 +1,29 @@ package app.revanced.patches.shared.settings.preference.impl import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.IResource import org.w3c.dom.Document -import org.w3c.dom.Element +// TODO: allow specifying an array resource file instead of using a list of StringResources /** - * Represents an array resource. + * An array resource. * * @param name The name of the array resource. * @param items The items of the array resource. */ -// TODO: allow specifying an array resource file instead of using a list of StringResources -internal data class ArrayResource( - override val name: String, +internal class ArrayResource( + name: String, val items: List<StringResource> -) : BaseResource(name) { - override val tag = "string-array" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { +) : BaseResource(name, "string-array") { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { setAttribute("name", name) items.forEach { item -> - resourceCallback?.invoke(item) + resourceCallback.invoke(item) this.appendChild(ownerDocument.createElement("item").also { itemNode -> itemNode.textContent = "@string/${item.name}" }) } } - } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt index 09432143b..7d3ec982d 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt @@ -1,6 +1,8 @@ package app.revanced.patches.shared.settings.preference.impl enum class InputType(val type: String) { - STRING("text"), + TEXT("text"), + TEXT_CAP_CHARACTERS("textCapCharacters"), + TEXT_MULTI_LINE("textMultiLine"), NUMBER("number"), } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt index 9f2f9f84e..3df3c87e9 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt @@ -1,11 +1,9 @@ package app.revanced.patches.shared.settings.preference.impl -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addDefault +import app.revanced.patches.shared.settings.preference.BaseResource +import app.revanced.patches.shared.settings.preference.DefaultBasePreference import app.revanced.patches.shared.settings.preference.addSummary import org.w3c.dom.Document -import org.w3c.dom.Element /** * List preference. @@ -14,25 +12,21 @@ import org.w3c.dom.Element * @param title The title of the list preference. * @param entries The human-readable entries of the list preference. * @param entryValues The entry values of the list preference. - * @param default The default entry value of the list preference. * @param summary The summary of the list preference. + * @param default The default entry value of the list preference. */ internal class ListPreference( key: String, title: StringResource, val entries: ArrayResource, val entryValues: ArrayResource, - val default: String? = null, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "ListPreference" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("android:entries", "@array/${entries.also { resourceCallback?.invoke(it) }.name}") - setAttribute("android:entryValues", "@array/${entryValues.also { resourceCallback?.invoke(it) }.name}") - addDefault(default) + summary: StringResource? = null, + default: String? = null, +) : DefaultBasePreference<String>(key, title, summary, "ListPreference", default) { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + setAttribute("android:entries", "@array/${entries.also { resourceCallback.invoke(it) }.name}") + setAttribute("android:entryValues", "@array/${entryValues.also { resourceCallback.invoke(it) }.name}") addSummary(summary) } - } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt index 9332bd17d..c97913c2a 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/NonInteractivePreference.kt @@ -1,24 +1,27 @@ package app.revanced.patches.shared.settings.preference.impl import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource +import app.revanced.patches.shared.settings.preference.BaseResource import app.revanced.patches.shared.settings.preference.addSummary import org.w3c.dom.Document import org.w3c.dom.Element /** - * A simple static title and summary that is not backed by any preference key/value, - * and cannot be changed by or interacted with by the user, + * A non interactive preference. + * + * Not backed by any preference key/value, + * and cannot be changed by or interacted with by the user. + * + * @param title The title of the preference. + * @param summary The summary of the text preference. */ internal class NonInteractivePreference( title: StringResource, - val summary: StringResource, -) : BasePreference("", title) { - override val tag: String = "Preference" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { + summary: StringResource, +) : BasePreference(null, title, summary, "Preference") { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element { return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary.also { resourceCallback?.invoke(it) + addSummary(summary?.also { resourceCallback.invoke(it) setAttribute("android:selectable", false.toString()) }) } diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt index fcacd61d7..2ada5625d 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt @@ -1,44 +1,41 @@ package app.revanced.patches.shared.settings.preference.impl import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addSummary +import app.revanced.patches.shared.settings.preference.BaseResource import org.w3c.dom.Document -import org.w3c.dom.Element /** - * A Preference object. + * A preference object. * + * @param key The key of the preference. * @param title The title of the preference. - * @param intent The intent of the preference. * @param summary The summary of the text preference. + * @param intent The intent of the preference. */ internal class Preference( key: String, title: StringResource, - val intent: Intent, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "Preference" - - /* Key-less constructor */ + summary: StringResource, + val intent: Intent +) : BasePreference(key, title, summary, "Preference") { constructor( title: StringResource, - intent: Intent, - summary: StringResource? = null - ) : this("", title, intent, summary) - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary?.also { resourceCallback?.invoke(it) }) + summary: StringResource, + intent: Intent + ) : this("", title, summary, intent) + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { this.appendChild(ownerDocument.createElement("intent").also { intentNode -> intentNode.setAttribute("android:targetPackage", intent.targetPackage) intentNode.setAttribute("android:data", intent.data) intentNode.setAttribute("android:targetClass", intent.targetClass) }) } - } - data class Intent(val targetPackage: String, val data: String, val targetClass: String) + internal class Intent( + internal val targetPackage: String, + internal val data: String, + internal val targetClass: String + ) } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt index f575dfe3a..56e02f45d 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt @@ -1,12 +1,11 @@ package app.revanced.patches.shared.settings.preference.impl import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource +import app.revanced.patches.shared.settings.preference.BaseResource import org.w3c.dom.Document -import org.w3c.dom.Element /** - * Preference category. + * A preference category. * * @param key The key of the preference. * @param title The title of the preference. @@ -15,15 +14,13 @@ import org.w3c.dom.Element internal open class PreferenceCategory( key: String, title: StringResource, - var preferences: List<BasePreference> -) : BasePreference(key, title) { - override val tag: String = "PreferenceCategory" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { + var preferences: List<BasePreference>, + tag: String = "PreferenceCategory" +) : BasePreference(key, title, null, tag) { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { for (childPreference in preferences) { this.appendChild(childPreference.serialize(ownerDocument, resourceCallback)) } } - } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt index b7c82ba6f..e6bf32d43 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt @@ -1,13 +1,12 @@ package app.revanced.patches.shared.settings.preference.impl import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource +import app.revanced.patches.shared.settings.preference.BaseResource import app.revanced.patches.shared.settings.preference.addSummary import org.w3c.dom.Document -import org.w3c.dom.Element /** - * Preference screen. + * A preference screen. * * @param key The key of the preference. * @param title The title of the preference. @@ -18,17 +17,13 @@ internal open class PreferenceScreen( key: String, title: StringResource, var preferences: List<BasePreference>, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "PreferenceScreen" + summary: StringResource? = null +) : BasePreference(key, title, summary, "PreferenceScreen") { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { + addSummary(summary?.also { resourceCallback.invoke(it) }) - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary?.also { resourceCallback?.invoke(it) }) - - for (childPreference in preferences) { + for (childPreference in preferences) this.appendChild(childPreference.serialize(ownerDocument, resourceCallback)) - } } - } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt index 49471faa8..7934b1270 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt @@ -1,31 +1,27 @@ package app.revanced.patches.shared.settings.preference.impl import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.IResource import org.w3c.dom.Document -import org.w3c.dom.Element /** - * Represents a string value in the strings.xml file + * A string value. + * Represets a string in the strings.xml file. * - * @param name The name of the string - * @param value The value of the string - * @param formatted If the string is formatted. If false, the attribute will be set + * @param name The name of the string. + * @param value The value of the string. + * @param formatted If the string is formatted. If false, the attribute will be set. */ -internal data class StringResource( - override val name: String, +internal class StringResource( + name: String, val value: String, val formatted: Boolean = true -) : BaseResource(name) { - override val tag = "string" +) : BaseResource(name, "string") { - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { // if the string is un-formatted, explicitly add the formatted attribute - if (!formatted) - setAttribute("formatted", "false") + if (!formatted) setAttribute("formatted", "false") textContent = value } - } } diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt index 2845849bc..5a9e6778e 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt @@ -1,37 +1,36 @@ package app.revanced.patches.shared.settings.preference.impl -import app.revanced.patches.shared.settings.preference.* +import app.revanced.patches.shared.settings.preference.BaseResource +import app.revanced.patches.shared.settings.preference.DefaultBasePreference +import app.revanced.patches.shared.settings.preference.SummaryType +import app.revanced.patches.shared.settings.preference.addSummary import app.revanced.patches.shared.settings.resource.patch.AbstractSettingsResourcePatch.Companion.include import org.w3c.dom.Document import org.w3c.dom.Element /** - * Switch preference. + * A switch preference. * * @param key The key of the switch. * @param title The title of the switch. - * @param default The default value of the switch. * @param summaryOn The summary to show when the preference is enabled. * @param summaryOff The summary to show when the preference is disabled. * @param userDialogMessage The message to show in a dialog when the user toggles the preference. + * @param default The default value of the switch. */ internal class SwitchPreference( key: String, title: StringResource, - val default: Boolean = false, - val summaryOn: StringResource? = null, - val summaryOff: StringResource? = null, - val userDialogMessage: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "SwitchPreference" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - // dialog message is stored as a regular string and later referenced by SettingsEnum + val summaryOn: StringResource, + val summaryOff: StringResource, + val userDialogMessage: StringResource? = null, + default: Boolean = false, +) : DefaultBasePreference<Boolean>( key, title, null, "SwitchPreference", default) { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit): Element { userDialogMessage?.include() return super.serialize(ownerDocument, resourceCallback).apply { - addDefault(default) - addSummary(summaryOn?.also { resourceCallback?.invoke(it) }, SummaryType.ON) - addSummary(summaryOff?.also { resourceCallback?.invoke(it) }, SummaryType.OFF) + addSummary(summaryOn.also { resourceCallback.invoke(it) }, SummaryType.ON) + addSummary(summaryOff.also { resourceCallback.invoke(it) }, SummaryType.OFF) } } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt index 907a4a160..5895a5e6e 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt @@ -1,35 +1,29 @@ package app.revanced.patches.shared.settings.preference.impl -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addDefault -import app.revanced.patches.shared.settings.preference.addSummary +import app.revanced.patches.shared.settings.preference.BaseResource +import app.revanced.patches.shared.settings.preference.DefaultBasePreference import org.w3c.dom.Document -import org.w3c.dom.Element /** - * Text preference. + * A text preference. * * @param key The key of the text preference. * @param title The title of the text preference. * @param inputType The input type of the text preference. - * @param default The default value of the text preference. * @param summary The summary of the text preference. + * @param default The default value of the text preference. */ internal class TextPreference( - key: String, + key: String?, title: StringResource, - var inputType: InputType = InputType.STRING, - val default: String? = null, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "EditTextPreference" + summary: StringResource?, + val inputType: InputType = InputType.TEXT, + default: String? = null, + tag: String = "app.revanced.integrations.settingsmenu.ResettableEditTextPreference" +) : DefaultBasePreference<String>(key, title, summary, tag, default) { - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { + override fun serialize(ownerDocument: Document, resourceCallback: (BaseResource) -> Unit) = + super.serialize(ownerDocument, resourceCallback).apply { setAttribute("android:inputType", inputType.type) - addDefault(default) - addSummary(summary?.also { resourceCallback?.invoke(it) }) } - } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt index 778916b55..41ff37396 100644 --- a/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource +import app.revanced.patches.shared.settings.preference.BaseResource import app.revanced.patches.shared.settings.preference.addPreference import app.revanced.patches.shared.settings.preference.addResource import app.revanced.patches.shared.settings.preference.impl.ArrayResource @@ -108,7 +108,7 @@ abstract class AbstractSettingsResourcePatch( * * @throws IllegalArgumentException if the resource already exists. */ - internal fun IResource.include() { + internal fun BaseResource.include() { when (this) { is StringResource -> { if (strings.any { it.name == name }) return diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt index 88aae6a28..cc656d112 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt @@ -8,18 +8,13 @@ import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCompatibility import app.revanced.patches.spotify.audio.fingerprints.DisableCaptureRestrictionAudioDriverFingerprint import app.revanced.patches.spotify.audio.resource.patch.DisableCaptureRestrictionResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.MethodReference @Patch @Name("disable-capture-restriction") @@ -35,49 +30,16 @@ class DisableCaptureRestrictionBytecodePatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { val method = DisableCaptureRestrictionAudioDriverFingerprint.result!!.mutableMethod - var invokePosition: Int? = null - var invokeParamRegister: Int? = null - - // Find INVOKE_VIRTUAL opcode with call to AudioAttributesBuilder.setAllowedCapturePolicy(I) - for ((index, instruction) in method.implementation!!.instructions.withIndex()) { - if(instruction.opcode != Opcode.INVOKE_VIRTUAL) - continue - - val methodName = ((instruction as ReferenceInstruction).reference as MethodReference).name - if (methodName != "setAllowedCapturePolicy") - continue - - // Store register of the integer parameter for setAllowedCapturePolicy - invokeParamRegister = (instruction as FiveRegisterInstruction).registerD - invokePosition = index - } - - if(invokePosition == null || invokeParamRegister == null) - return PatchResultError("Cannot find setAllowedCapturePolicy method call") - - // Walk back to the const/4 instruction that sets the parameter register - var matchFound = false - for (index in invokePosition downTo 0) { - val instruction = method.instruction(index) - if(instruction.opcode != Opcode.CONST_4) - continue - - val register = (instruction as OneRegisterInstruction).registerA - if(register != invokeParamRegister) - continue - - // Replace parameter value - method.replaceInstruction( - index, "const/4 v$register, $ALLOW_CAPTURE_BY_ALL" + method.apply { + // Replace constant + val original = instruction(0) as OneRegisterInstruction + replaceInstruction( + 0, + "const/4 v${original.registerA}, $ALLOW_CAPTURE_BY_ALL" ) - matchFound = true - break } - return if (matchFound) - PatchResultSuccess() - else - PatchResultError("Const instruction not found") + return PatchResultSuccess() } private companion object { diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt index 191755518..97b9193e6 100644 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt @@ -1,10 +1,27 @@ package app.revanced.patches.spotify.audio.fingerprints +import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.MethodReference object DisableCaptureRestrictionAudioDriverFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass == "Lcom/spotify/playback/playbacknative/AudioDriver;" && methodDef.name == "constructAudioAttributes" + "L", + AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.SYNTHETIC or AccessFlags.BRIDGE, + listOf("L"), + listOf( + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT + ), + customFingerprint = { methodDef, _ -> + // Check for method call to AudioAttributes$Builder.setAllowedCapturePolicy Android API + methodDef.implementation?.instructions?.any { + ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "setAllowedCapturePolicy" + } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/syncforreddit/ads/annotations/DisableAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/syncforreddit/ads/annotations/DisableAdsCompatibility.kt new file mode 100644 index 000000000..c6cf42886 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/syncforreddit/ads/annotations/DisableAdsCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.syncforreddit.ads.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.laurencedawson.reddit_sync")]) +@Target(AnnotationTarget.CLASS) +internal annotation class DisableAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/syncforreddit/ads/fingerprints/IsAdsEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/syncforreddit/ads/fingerprints/IsAdsEnabledFingerprint.kt new file mode 100644 index 000000000..ff01b38cf --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/syncforreddit/ads/fingerprints/IsAdsEnabledFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.syncforreddit.ads.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object IsAdsEnabledFingerprint : MethodFingerprint( + returnType = "Z", + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, + strings = listOf("SyncIapHelper") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/syncforreddit/ads/patch/DisableAdsPatch.kt b/src/main/kotlin/app/revanced/patches/syncforreddit/ads/patch/DisableAdsPatch.kt new file mode 100644 index 000000000..ef5e2a945 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/syncforreddit/ads/patch/DisableAdsPatch.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.syncforreddit.ads.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.syncforreddit.ads.annotations.DisableAdsCompatibility +import app.revanced.patches.syncforreddit.ads.fingerprints.IsAdsEnabledFingerprint +import app.revanced.patches.syncforreddit.detection.piracy.patch.DisablePiracyDetectionPatch + +@Patch +@Name("disable-ads") +@DependsOn([DisablePiracyDetectionPatch::class]) +@Description("Disables ads.") +@Version("0.0.1") +@DisableAdsCompatibility +class DisableAdsPatch : BytecodePatch(listOf(IsAdsEnabledFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + IsAdsEnabledFingerprint.result?.mutableMethod?.apply { + addInstructions( + 0, + """ + const/4 v0, 0x0 + return v0 + """ + ) + } ?: return IsAdsEnabledFingerprint.toErrorResult() + + return PatchResultSuccess() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/syncforreddit/detection/piracy/fingerprints/PiracyDetectionFingerprint.kt b/src/main/kotlin/app/revanced/patches/syncforreddit/detection/piracy/fingerprints/PiracyDetectionFingerprint.kt new file mode 100644 index 000000000..d3c87f360 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/syncforreddit/detection/piracy/fingerprints/PiracyDetectionFingerprint.kt @@ -0,0 +1,29 @@ +package app.revanced.patches.syncforreddit.detection.piracy.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.TypeReference + +object PiracyDetectionFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + opcodes = listOf( + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.INVOKE_VIRTUAL + ), + customFingerprint = { method, _ -> + method.implementation?.instructions?.any { + if (it.opcode != Opcode.NEW_INSTANCE) return@any false + + val reference = (it as ReferenceInstruction).reference + + reference.toString() == "Lcom/github/javiersantos/piracychecker/PiracyChecker;" + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/syncforreddit/detection/piracy/patch/DisablePiracyDetectionPatch.kt b/src/main/kotlin/app/revanced/patches/syncforreddit/detection/piracy/patch/DisablePiracyDetectionPatch.kt new file mode 100644 index 000000000..ad7f2f9a1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/syncforreddit/detection/piracy/patch/DisablePiracyDetectionPatch.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.syncforreddit.detection.piracy.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.syncforreddit.detection.piracy.fingerprints.PiracyDetectionFingerprint + +@Description("Disables detection of modified versions.") +@Version("0.0.1") +class DisablePiracyDetectionPatch : BytecodePatch(listOf(PiracyDetectionFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + PiracyDetectionFingerprint.result?.mutableMethod?.apply { + addInstructions( + 0, + """ + return-void + """ + ) + } ?: return PiracyDetectionFingerprint.toErrorResult() + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt index dccab403f..0f019f078 100644 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.ticktick.misc.themeunlock.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object CheckLockedThemesFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("Theme;") && methodDef.name == "isLockedTheme" } ) diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt index dc22b02c5..f5e8430d0 100644 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.ticktick.misc.themeunlock.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SetThemeFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("ThemePreviewActivity;") && methodDef.name == "lambda\$updateUserBtn\$1" } ) diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt index 8cc8fdd9c..d61f3539c 100644 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt +++ b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt @@ -36,7 +36,7 @@ class UnlockProPatch : BytecodePatch( ) val setThemeMethod = SetThemeFingerprint.result!!.mutableMethod - setThemeMethod.removeInstructions(0, 9) + setThemeMethod.removeInstructions(0, 10) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt index fc252a24c..4f68c3819 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.ad.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object ConvertHelpFeedItemListFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/ConvertHelp;") && methodDef.name.endsWith("${'$'}FeedItemList") } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt index 4f9de5d3a..a3544cb1c 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.ad.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object FeedItemListCloneFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/FeedItemList;") && methodDef.name == "clone" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt index 667e5abcd..30854e0c3 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt @@ -5,8 +5,8 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags object FeedApiServiceLIZFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.SYNTHETIC, - customFingerprint = { methodDef -> + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.SYNTHETIC, + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/FeedApiService;") && methodDef.name == "LIZ" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt index f1e851661..d5219ff3c 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.AccessFlags object ACLCommonShareFingerprint : MethodFingerprint( "I", AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/ACLCommonShare;") && methodDef.name == "getCode" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt index 384530db7..39e1a7171 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt @@ -13,7 +13,7 @@ import org.jf.dexlib2.AccessFlags object ACLCommonShareFingerprint2 : MethodFingerprint( "I", AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/ACLCommonShare;") && methodDef.name == "getShowType" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt index cf585dd21..13e4d61c5 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt @@ -13,7 +13,7 @@ import org.jf.dexlib2.AccessFlags object ACLCommonShareFingerprint3 : MethodFingerprint( "I", AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/ACLCommonShare;") && methodDef.name == "getTranscode" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt index fb6463186..a71d6c887 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags object AwemeGetVideoControlFingerprint : MethodFingerprint( "L", AccessFlags.PUBLIC.value, - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/Aweme;") && methodDef.name == "getVideoControl" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt index 4e70ca812..2a395194b 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags object SpeedControlParentFingerprint : MethodFingerprint( returnType = "L", - access = AccessFlags.PRIVATE or AccessFlags.FINAL, + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, parameters = listOf( "L" ), diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt index 9afc4eccf..b4d095976 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.misc.integrations.fingerprints import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint object InitFingerprint : IntegrationsFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/AwemeHostApplication;") && methodDef.name == "onCreate" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt index 842dcae2d..950c25835 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt @@ -2,7 +2,7 @@ package app.revanced.patches.tiktok.misc.login.disablerequirement.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object MandatoryLoginServiceFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/MandatoryLoginService;") && methodDef.name == "enableForcedLogin" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt index 59015a6b6..9f6de329e 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt @@ -9,7 +9,7 @@ import app.revanced.patches.tiktok.misc.login.disablerequirement.annotations.Dis @DisableLoginRequirementCompatibility @Version("0.0.1") object MandatoryLoginServiceFingerprint2 : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/MandatoryLoginService;") && methodDef.name == "shouldShowForcedLogin" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt index 2e1a1eaf1..24dd8a7de 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt @@ -6,9 +6,9 @@ import org.jf.dexlib2.AccessFlags object GoogleAuthAvailableFingerprint : MethodFingerprint( returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf(), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/bytedance/lobby/google/GoogleAuth;" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt index 26e51a522..fb677fcb6 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt @@ -6,9 +6,9 @@ import org.jf.dexlib2.AccessFlags object GoogleOneTapAuthAvailableFingerprint : MethodFingerprint( returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf(), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/bytedance/lobby/google/GoogleOneTapAuth;" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt index 69778a650..b9b524d6b 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.misc.settings.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object AdPersonalizationActivityOnCreateFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/AdPersonalizationActivity;") && methodDef.name == "onCreate" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt index 46f2ba697..a2d655ab3 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.misc.settings.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SettingsOnViewCreatedFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/SettingNewVersionFragment;") && methodDef.name == "onViewCreated" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt index c2f1d3c51..b1e3bb5d0 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.tiktok.misc.settings.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SettingsStatusLoadFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("Lapp/revanced/tiktok/settingsmenu/SettingsStatus;") && methodDef.name == "load" } diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt index 0fcd0943d..42cd5a0d5 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt @@ -25,7 +25,6 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.formats.Instruction35c import org.jf.dexlib2.iface.reference.StringReference -import org.jf.dexlib2.iface.reference.TypeReference @Patch @DependsOn([IntegrationsPatch::class]) @@ -96,7 +95,7 @@ class SettingsPatch : BytecodePatch( private fun patchOptionNameAndOnClickEvent(index: Int, context: BytecodeContext) { with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) { // Patch option name - val overrideRegister = (instruction(index - 4) as OneRegisterInstruction).registerA + val overrideRegister = instruction<OneRegisterInstruction>(index - 4).registerA replaceInstruction( index - 4, """ @@ -105,16 +104,14 @@ class SettingsPatch : BytecodePatch( ) // Patch option OnClick Event - with(((instruction(index) as ReferenceInstruction).reference as TypeReference).type) { - context.findClass(this)!!.mutableClass.methods.first { it.name == "onClick" } - .addInstructions( - 0, - """ - invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V - return-void - """ - ) - } + val type = instruction<ReferenceInstruction>(index).reference.toString() + context.findClass(type)!!.mutableClass.methods.first { type == "onClick" }.addInstructions( + 0, + """ + invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V + return-void + """ + ) } } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt index 822a2e2fb..d193ab61d 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt @@ -97,14 +97,14 @@ class SpoofSimPatch : BytecodePatch() { // Patch Android API and return fake sim information private fun MutableMethod.replaceReference(index: Int, replacement: String) { - val resultReg = (instruction(index + 1) as OneRegisterInstruction).registerA + val resultReg = instruction<OneRegisterInstruction>(index + 1).registerA addInstructions( index + 2, - """ - invoke-static {v$resultReg}, Lapp/revanced/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$resultReg - """ + """ + invoke-static {v$resultReg}, Lapp/revanced/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$resultReg + """ ) } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/trakt/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/trakt/annotations/UnlockProCompatibility.kt new file mode 100644 index 000000000..aa619bd8c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/trakt/annotations/UnlockProCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.trakt.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("tv.trakt.trakt")]) +@Target(AnnotationTarget.CLASS) +internal annotation class UnlockProCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/trakt/fingerprints/IsVIPEPFingerprint.kt b/src/main/kotlin/app/revanced/patches/trakt/fingerprints/IsVIPEPFingerprint.kt new file mode 100644 index 000000000..f62cfe5fc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/trakt/fingerprints/IsVIPEPFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.trakt.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object IsVIPEPFingerprint : MethodFingerprint( + customFingerprint = custom@{ methodDef, _ -> + if (!methodDef.definingClass.endsWith("RealmUserSettings;")) return@custom false + + methodDef.name == "isVIPEP" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/trakt/fingerprints/IsVIPFingerprint.kt b/src/main/kotlin/app/revanced/patches/trakt/fingerprints/IsVIPFingerprint.kt new file mode 100644 index 000000000..eb678d260 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/trakt/fingerprints/IsVIPFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.trakt.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object IsVIPFingerprint : MethodFingerprint( + customFingerprint = custom@{ methodDef, _ -> + if (!methodDef.definingClass.endsWith("RealmUserSettings;")) return@custom false + + methodDef.name == "isVIP" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/trakt/fingerprints/RealmUserSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/trakt/fingerprints/RealmUserSettingsFingerprint.kt new file mode 100644 index 000000000..dd8c8198e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/trakt/fingerprints/RealmUserSettingsFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.trakt.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object RealmUserSettingsFingerprint : MethodFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("RealmUserSettings;") + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/trakt/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/trakt/patch/UnlockProPatch.kt new file mode 100644 index 000000000..362b91335 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/trakt/patch/UnlockProPatch.kt @@ -0,0 +1,52 @@ +package app.revanced.patches.trakt.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.trakt.annotations.UnlockProCompatibility +import app.revanced.patches.trakt.fingerprints.IsVIPEPFingerprint +import app.revanced.patches.trakt.fingerprints.IsVIPFingerprint +import app.revanced.patches.trakt.fingerprints.RealmUserSettingsFingerprint + +@Patch +@Name("unlock-pro") +@Description("Unlocks pro features.") +@UnlockProCompatibility +@Version("0.0.1") +class UnlockProPatch : BytecodePatch( + listOf(RealmUserSettingsFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + RealmUserSettingsFingerprint.result?.classDef?.let { realUserSettingsClass -> + arrayOf(IsVIPFingerprint, IsVIPEPFingerprint).onEach { fingerprint -> + // Resolve both fingerprints on the same class. + if (!fingerprint.resolve(context, realUserSettingsClass)) + throw fingerprint.toErrorResult() + }.forEach { fingerprint -> + // Return true for both VIP check methods. + fingerprint.result?.mutableMethod?.addInstructions(0, RETURN_TRUE_INSTRUCTIONS) + ?: return fingerprint.toErrorResult() + } + } ?: return RealmUserSettingsFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + private companion object { + const val RETURN_TRUE_INSTRUCTIONS = + """ + const/4 v0, 0x1 + invoke-static {v0}, Ljava/lang/Boolean;->valueOf(Z)Ljava/lang/Boolean; + move-result-object v1 + return-object v1 + """ + } +} \ No newline at end of file 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 index c85e6c92e..76821975f 100644 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/MethodUnlockFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/fingerprints/MethodUnlockFingerprint.kt @@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint abstract class MethodUnlockFingerprint(private val className: String) : MethodFingerprint( "L", strings = listOf("binding.addButton"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/$className;") } ) diff --git a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/patch/UnlockPaidWidgetsPatch.kt b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/patch/UnlockPaidWidgetsPatch.kt index 8a188600f..16455a4c5 100644 --- a/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/patch/UnlockPaidWidgetsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twelvewidgets/unlock/patch/UnlockPaidWidgetsPatch.kt @@ -38,7 +38,7 @@ class UnlockPaidWidgetsPatch : BytecodePatch( fingerprint.result?.mutableMethod ?: return fingerprint.toErrorResult() }.forEach { method -> method.apply { - removeInstructions(4, 2) + removeInstructions(4, 3) addInstructions( implementation?.instructions?.size!!, """ const/4 v1, 0x0 diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt index 56bdf6286..fc7192cc1 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.twitch.ad.audio.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object AudioAdsPresenterPlayFingerprint : MethodFingerprint( - customFingerprint = { method -> + customFingerprint = { method, _ -> method.definingClass.endsWith("AudioAdsPlayerPresenter;") && method.name == "playAd" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt index a5cccb1c7..74cbff08b 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt @@ -50,7 +50,6 @@ class AudioAdsPatch : BytecodePatch( "revanced_block_audio_ads", "Block audio ads" ), - true, StringResource( "revanced_block_audio_ads_on", "Audio ads are blocked" @@ -59,6 +58,7 @@ class AudioAdsPatch : BytecodePatch( "revanced_block_audio_ads_off", "Audio ads are unblocked" ), + default = true, ) ) diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt index 348044040..d47628827 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.ad.embedded.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object CreateUsherClientFingerprint : MethodFingerprint( - customFingerprint = { method -> + customFingerprint = { method, _ -> method.definingClass.endsWith("Ltv/twitch/android/network/OkHttpClientFactory;") && method.name == "buildOkHttpClient" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt index 5384546a4..23debc540 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt @@ -66,7 +66,7 @@ class EmbeddedAdsPatch : BytecodePatch( StringResource("key_revanced_proxy_purpleadblock", "purpleadblock") ) ), - "ttv-lol" + default = "ttv-lol" ) ) diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt index 04c1c09b1..31ea27485 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt @@ -8,7 +8,7 @@ object CheckAdEligibilityLambdaFingerprint : MethodFingerprint( "L", AccessFlags.PRIVATE or AccessFlags.FINAL or AccessFlags.STATIC, listOf("L", "L", "L"), - customFingerprint = { method -> + customFingerprint = { method, _ -> method.definingClass.endsWith("AdEligibilityFetcher;") && method.name.contains("shouldRequestAd") } diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt index ed38035eb..f64ba6ffe 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.twitch.ad.video.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object ContentConfigShowAdsFingerprint : MethodFingerprint( - customFingerprint = { method -> + customFingerprint = { method, _ -> method.definingClass.endsWith("ContentConfigData;") && method.name == "getShowAds" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt index 3256ad024..0f7b2454c 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.ad.video.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object GetReadyToShowAdFingerprint : MethodFingerprint( - customFingerprint = { method -> + customFingerprint = { method, _ -> method.definingClass.endsWith("/StreamDisplayAdsPresenter;") && method.name == "getReadyToShowAdOrAbort" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt index 9b1197e78..8094c03f5 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt @@ -132,7 +132,6 @@ class VideoAdsPatch : AbstractAdPatch( "revanced_block_video_ads", "Block video ads" ), - true, StringResource( "revanced_block_video_ads_on", "Video ads are blocked" @@ -141,6 +140,7 @@ class VideoAdsPatch : AbstractAdPatch( "revanced_block_video_ads_off", "Video ads are unblocked" ), + default = true ) ) diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt index 733710b2b..5d5bfe492 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.chat.antidelete.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object ChatUtilCreateDeletedSpanFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/ChatUtil\$Companion;") && methodDef.name == "createDeletedSpanFromChatMessageSpan" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt index 6ecb63cbd..49e02dd7a 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags object DeletedMessageClickableSpanCtorFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("DeletedMessageClickableSpan;") } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt index 7e8ee66a3..12ca4da9f 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.twitch.chat.antidelete.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SetHasModAccessFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("DeletedMessageClickableSpan;") && methodDef.name == "setHasModAccess" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt index dba6e833e..dd69b4da1 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt @@ -4,8 +4,12 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.* -import app.revanced.patcher.patch.* +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.smali.ExternalLabel @@ -13,7 +17,9 @@ import app.revanced.patches.shared.settings.preference.impl.ArrayResource import app.revanced.patches.shared.settings.preference.impl.ListPreference import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.twitch.chat.antidelete.annotations.ShowDeletedMessagesCompatibility -import app.revanced.patches.twitch.chat.antidelete.fingerprints.* +import app.revanced.patches.twitch.chat.antidelete.fingerprints.ChatUtilCreateDeletedSpanFingerprint +import app.revanced.patches.twitch.chat.antidelete.fingerprints.DeletedMessageClickableSpanCtorFingerprint +import app.revanced.patches.twitch.chat.antidelete.fingerprints.SetHasModAccessFingerprint import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch @@ -92,7 +98,7 @@ class ShowDeletedMessagesPatch : BytecodePatch( StringResource("key_revanced_deleted_messages_cross_out", "cross-out") ) ), - "cross-out" + default = "cross-out" ) ) diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/annotations/AutoClaimChannelPointsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/annotations/AutoClaimChannelPointsCompatibility.kt new file mode 100644 index 000000000..30473cf3a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/annotations/AutoClaimChannelPointsCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.twitch.chat.autoclaim.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("tv.twitch.android.app")]) +@Target(AnnotationTarget.CLASS) +internal annotation class AutoClaimChannelPointsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/fingerprints/CommunityPointsButtonViewDelegateFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/fingerprints/CommunityPointsButtonViewDelegateFingerprint.kt new file mode 100644 index 000000000..5bbfaeb00 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/fingerprints/CommunityPointsButtonViewDelegateFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.twitch.chat.autoclaim.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object CommunityPointsButtonViewDelegateFingerprint : MethodFingerprint( + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("CommunityPointsButtonViewDelegate;") + && methodDef.name == "showClaimAvailable" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/patch/AutoClaimChannelPointsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/patch/AutoClaimChannelPointsPatch.kt new file mode 100644 index 000000000..210a4950b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitch/chat/autoclaim/patch/AutoClaimChannelPointsPatch.kt @@ -0,0 +1,70 @@ +package app.revanced.patches.twitch.chat.autoclaim.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.twitch.chat.autoclaim.annotations.AutoClaimChannelPointsCompatibility +import app.revanced.patches.twitch.chat.autoclaim.fingerprints.CommunityPointsButtonViewDelegateFingerprint +import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch + +@Patch +@DependsOn([SettingsPatch::class]) +@Name("auto-claim-channel-points") +@Description("Automatically claim Channel Points.") +@AutoClaimChannelPointsCompatibility +@Version("0.0.1") +class AutoClaimChannelPointPatch : BytecodePatch( + listOf(CommunityPointsButtonViewDelegateFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences( + SwitchPreference( + "revanced_auto_claim_channel_points", + StringResource( + "revanced_auto_claim_channel_points", + "Automatically claim Channel Points" + ), + StringResource( + "revanced_auto_claim_channel_points_on", + "Channel Points are claimed automatically" + ), + StringResource( + "revanced_auto_claim_channel_points_off", + "Channel Points are not claimed automatically" + ), + default = true + ) + ) + + CommunityPointsButtonViewDelegateFingerprint.result?.mutableMethod?.apply { + val lastIndex = implementation!!.instructions.lastIndex + addInstructions( + lastIndex, // place in front of return-void + """ + invoke-static {}, Lapp/revanced/twitch/patches/AutoClaimChannelPointsPatch;->shouldAutoClaim()Z + move-result v0 + if-eqz v0, :auto_claim + + # Claim by calling the button's onClick method + + iget-object v0, p0, Ltv/twitch/android/shared/community/points/viewdelegate/CommunityPointsButtonViewDelegate;->buttonLayout:Landroid/view/ViewGroup; + invoke-virtual { v0 }, Landroid/view/View;->callOnClick()Z + """, + listOf(ExternalLabel("auto_claim", instruction(lastIndex))) + ) + } ?: return CommunityPointsButtonViewDelegateFingerprint.toErrorResult() + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt index e7a317849..145bc06be 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.twitch.debug.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object IsDebugConfigEnabledFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "isDebugConfigEnabled" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt index cf8f1f759..ab50280a5 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.twitch.debug.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object IsOmVerificationEnabledFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "isOmVerificationEnabled" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt index 12c5de043..e9a77cc3b 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.twitch.debug.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object ShouldShowDebugOptionsFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "shouldShowDebugOptions" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt index 755efe696..5c864ba8b 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt @@ -59,7 +59,6 @@ class DebugModePatch : BytecodePatch( "revanced_debug_mode_enable", "Enable debug mode" ), - false, StringResource( "revanced_debug_mode_on", "Debug mode is enabled (not recommended)" @@ -68,6 +67,7 @@ class DebugModePatch : BytecodePatch( "revanced_debug_mode_off", "Debug mode is disabled" ), + default = false, ) ) diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt index 7f55dd22f..258db9902 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt @@ -9,7 +9,7 @@ import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch. @IntegrationsCompatibility @Version("0.0.1") object InitFingerprint : IntegrationsFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/TwitchApplication;") && methodDef.name == "onCreate" } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt index d0f8b7214..f700354f7 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt @@ -4,7 +4,9 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.* +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult @@ -18,8 +20,10 @@ import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.twitch.misc.settings.annotations.SettingsCompatibility -import app.revanced.patches.twitch.misc.settings.components.CustomPreferenceCategory -import app.revanced.patches.twitch.misc.settings.fingerprints.* +import app.revanced.patches.twitch.misc.settings.fingerprints.MenuGroupsOnClickFingerprint +import app.revanced.patches.twitch.misc.settings.fingerprints.MenuGroupsUpdatedFingerprint +import app.revanced.patches.twitch.misc.settings.fingerprints.SettingsActivityOnCreateFingerprint +import app.revanced.patches.twitch.misc.settings.fingerprints.SettingsMenuItemEnumFingerprint import app.revanced.patches.twitch.misc.settings.resource.patch.SettingsResourcePatch import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.immutable.ImmutableField @@ -178,10 +182,11 @@ class SettingsPatch : BytecodePatch( internal inner class CustomCategory(key: String, title: String) : Screen.Category(key, title) { /* For Twitch, we need to load our CustomPreferenceCategory class instead of the default one. */ override fun transform(): PreferenceCategory { - return CustomPreferenceCategory( + return PreferenceCategory( key, StringResource("${key}_title", title), - preferences.sortedBy { it.title.value } + preferences.sortedBy { it.title.value }, + "app.revanced.twitch.settingsmenu.preference.CustomPreferenceCategory" ) } } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/components/CustomPreferenceCategory.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/components/CustomPreferenceCategory.kt deleted file mode 100644 index 20c7bdb80..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/components/CustomPreferenceCategory.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.components - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.impl.PreferenceCategory -import app.revanced.patches.shared.settings.preference.impl.StringResource - -/** - * Customized preference category for Twitch. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param preferences Child preferences of this category. - */ -internal open class CustomPreferenceCategory( - key: String, - title: StringResource, - preferences: List<BasePreference> -) : PreferenceCategory(key, title, preferences) { - override val tag: String = "app.revanced.twitch.settingsmenu.preference.CustomPreferenceCategory" -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt index 1a6375986..6bf971dd6 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt @@ -8,7 +8,7 @@ object MenuGroupsOnClickFingerprint : MethodFingerprint( "V", AccessFlags.PRIVATE or AccessFlags.STATIC or AccessFlags.FINAL, listOf("L", "L", "L"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/SettingsMenuViewDelegate;") && methodDef.name.contains("render") } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt index 913f31d14..42cc4e466 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.misc.settings.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object MenuGroupsUpdatedFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/SettingsMenuPresenter\$Event\$MenuGroupsUpdated;") && methodDef.name == "<init>" } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt index f976f0210..ed30aa4eb 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.misc.settings.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SettingsActivityOnCreateFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/SettingsActivity;") && methodDef.name == "onCreate" } diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt index cdb2dd177..cbee9a584 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitch.misc.settings.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SettingsMenuItemEnumFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("/SettingsMenuItem;") && methodDef.name == "<clinit>" } ) diff --git a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/InlineActionTypesFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/InlineActionTypesFingerprint.kt index eb4f86a25..8cb634e7d 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/InlineActionTypesFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/InlineActionTypesFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags object InlineActionTypesFingerprint : MethodFingerprint( returnType = "Ljava/util/List", - access = AccessFlags.PUBLIC or AccessFlags.STATIC, + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, strings = listOf( "getCurrentMemoizing()", "android_animated_reply_icon_enabled", diff --git a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerConstructorFingerprint.kt index dda7c74cc..811dd497e 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerConstructorFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode object TweetStatsContainerConstructorFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, parameters = listOf("L"), opcodes = listOf( Opcode.INVOKE_DIRECT, diff --git a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerWrapperConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerWrapperConstructorFingerprint.kt index 791e15162..3c93ceda6 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerWrapperConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsContainerWrapperConstructorFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode object TweetStatsContainerWrapperConstructorFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, parameters = listOf("L"), opcodes = listOf( Opcode.INVOKE_DIRECT, diff --git a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsViewDelegateBinderFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsViewDelegateBinderFingerprint.kt index 3d3f845b4..970f7e81b 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsViewDelegateBinderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/fingerprints/TweetStatsViewDelegateBinderFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode object TweetStatsViewDelegateBinderFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf( Opcode.NEW_INSTANCE, Opcode.CONST_16, diff --git a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/patch/HideViewsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/patch/HideViewsBytecodePatch.kt index 3752d0798..b8cb63652 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/patch/HideViewsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/layout/hideviews/patch/HideViewsBytecodePatch.kt @@ -61,7 +61,7 @@ class HideViewsBytecodePatch : BytecodePatch( TweetStatsContainerConstructorFingerprint, returnFingerprint ) { patternScanResult, method -> - method.removeInstructions(patternScanResult.endIndex - 3, 2) + method.removeInstructions(patternScanResult.endIndex - 3, 3) } } @@ -80,13 +80,13 @@ class HideViewsBytecodePatch : BytecodePatch( TweetStatsContainerWrapperConstructorFingerprint, wrapperReturnFingerprint ) { patternScanResult, method -> - method.removeInstructions(patternScanResult.startIndex - 4, 3) + method.removeInstructions(patternScanResult.startIndex - 4, 4) } } private fun removeViewDelegateBinderSubscription() { transformMethod(TweetStatsViewDelegateBinderFingerprint) { result, method -> - method.removeInstructions(result.scanResult.patternScanResult!!.startIndex - 4, 9) + method.removeInstructions(result.scanResult.patternScanResult!!.startIndex - 4, 10) } } diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonHookPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonHookPatchFingerprint.kt index cc533162d..732e7fb6f 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonHookPatchFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonHookPatchFingerprint.kt @@ -4,6 +4,10 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode object JsonHookPatchFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> methodDef.name == "<clinit>" }, - opcodes = listOf(Opcode.IGET_OBJECT) + customFingerprint = { methodDef, _ -> methodDef.name == "<clinit>" }, + opcodes = listOf( + Opcode.INVOKE_INTERFACE, // Add dummy hook to hooks list. + // Add hooks to the hooks list. + Opcode.INVOKE_STATIC // Call buildList. + ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonInputStreamFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonInputStreamFingerprint.kt index 7c80f5bde..f8f1b4c8d 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonInputStreamFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/JsonInputStreamFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.twitter.misc.hook.json.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object JsonInputStreamFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> if (methodDef.parameterTypes.size == 0) false else methodDef.parameterTypes.first() == "Ljava/io/InputStream;" } diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/LoganSquareFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/LoganSquareFingerprint.kt index 98f0a82f6..5eb6f5aec 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/LoganSquareFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/fingerprints/LoganSquareFingerprint.kt @@ -3,5 +3,5 @@ package app.revanced.patches.twitter.misc.hook.json.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object LoganSquareFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> methodDef.definingClass.endsWith("LoganSquare;") } + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("LoganSquare;") } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/patch/JsonHookPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/patch/JsonHookPatch.kt index c604c6810..8a14dc9ce 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/patch/JsonHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/json/patch/JsonHookPatch.kt @@ -5,13 +5,18 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.removeInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.RequiresIntegrations import app.revanced.patches.twitter.misc.hook.json.fingerprints.JsonHookPatchFingerprint import app.revanced.patches.twitter.misc.hook.json.fingerprints.JsonInputStreamFingerprint import app.revanced.patches.twitter.misc.hook.json.fingerprints.LoganSquareFingerprint +import java.io.Closeable import java.io.InvalidClassException @Name("json-hook") @@ -20,16 +25,16 @@ import java.io.InvalidClassException @RequiresIntegrations class JsonHookPatch : BytecodePatch( listOf(LoganSquareFingerprint) -) { +), Closeable { override fun execute(context: BytecodeContext): PatchResult { - // Make sure the integrations are present. - val jsonHookPatch = context.findClass { it.type == JSON_HOOK_PATCH_CLASS_DESCRIPTOR } - ?: return PatchResultError("Could not find integrations.") + JsonHookPatchFingerprint.also { + // Make sure the integrations are present. + val jsonHookPatch = context.findClass { classDef -> classDef.type == JSON_HOOK_PATCH_CLASS_DESCRIPTOR } + ?: throw PatchResultError("Could not find integrations.") - // Allow patch to inject hooks into the patches integrations. - jsonHookPatchFingerprintResult = JsonHookPatchFingerprint.also { - it.resolve(context, jsonHookPatch.immutableClass) - }.result ?: return PatchResultError("Unexpected integrations.") + if (!it.resolve(context, jsonHookPatch.immutableClass)) + throw PatchResultError("Unexpected integrations.") + }.let { hooks = JsonHookPatchHook(it) } // Conveniently find the type to hook a method in, via a named field. val jsonFactory = LoganSquareFingerprint.result @@ -64,30 +69,10 @@ class JsonHookPatch : BytecodePatch( * * @param context The [BytecodeContext] of the current patch. * @param descriptor The class descriptor of the hook. + * @throws ClassNotFoundException If the class could not be found. */ - internal class Hook(context: BytecodeContext, private val descriptor: String) { - private var added = false - - /** - * Add the hook. - */ - internal fun add() { - if (added) return - - jsonHookPatchFingerprintResult.apply { - mutableMethod.apply { - addInstructions( - scanResult.patternScanResult!!.startIndex, - """ - sget-object v1, $descriptor->INSTANCE:$descriptor - invoke-virtual {v0, v1}, Lkotlin/collections/builders/ListBuilder;->add(Ljava/lang/Object;)Z - """ - ) - } - } - - added = true - } + internal class Hook(context: BytecodeContext, internal val descriptor: String) { + internal var added = false init { context.findClass { it.type == descriptor }?.let { @@ -102,15 +87,67 @@ class JsonHookPatch : BytecodePatch( } } - private companion object { - const val JSON_HOOK_CLASS_NAMESPACE = "app/revanced/twitter/patches/hook/json" + /** + * A hook for the [JsonHookPatch]. + * + * @param jsonHookPatchFingerprint The [JsonHookPatchFingerprint] to hook. + */ + internal class JsonHookPatchHook(jsonHookPatchFingerprint: MethodFingerprint): Closeable { + private val jsonHookPatchFingerprintResult = jsonHookPatchFingerprint.result!! + private val jsonHookPatchIndex = jsonHookPatchFingerprintResult.scanResult.patternScanResult!!.endIndex - const val JSON_HOOK_PATCH_CLASS_DESCRIPTOR = "L$JSON_HOOK_CLASS_NAMESPACE/JsonHookPatch;" + /** + * Add a hook to the [JsonHookPatch]. + * Will not add the hook if it's already added. + * + * @param hook The [Hook] to add. + */ + fun addHook(hook: Hook) { + if (hook.added) return - const val BASE_PATCH_CLASS_NAME = "BaseJsonHook" + jsonHookPatchFingerprintResult.mutableMethod.apply { + // Insert hooks right before calling buildList. + val insertIndex = jsonHookPatchIndex - const val JSON_HOOK_CLASS_DESCRIPTOR = "L$JSON_HOOK_CLASS_NAMESPACE/$BASE_PATCH_CLASS_NAME;" + addInstructions( + insertIndex, + """ + sget-object v1, ${hook.descriptor}->INSTANCE:${hook.descriptor} + invoke-interface {v0, v1}, Ljava/util/List;->add(Ljava/lang/Object;)Z + """ + ) + } - private lateinit var jsonHookPatchFingerprintResult: MethodFingerprintResult + hook.added = true + } + + override fun close() { + // Remove hooks.add(dummyHook). + jsonHookPatchFingerprintResult.mutableMethod.apply { + val addDummyHookIndex = jsonHookPatchIndex - 2 + + removeInstructions(addDummyHookIndex, 2) + } + } } + + override fun close() = hooks.close() + + internal companion object { + private const val JSON_HOOK_CLASS_NAMESPACE = "app/revanced/twitter/patches/hook/json" + + private const val JSON_HOOK_PATCH_CLASS_DESCRIPTOR = "L$JSON_HOOK_CLASS_NAMESPACE/JsonHookPatch;" + + private const val BASE_PATCH_CLASS_NAME = "BaseJsonHook" + + private const val JSON_HOOK_CLASS_DESCRIPTOR = "L$JSON_HOOK_CLASS_NAMESPACE/$BASE_PATCH_CLASS_NAME;" + + /** + * The [JsonHookPatchHook] of the [JsonHookPatch]. + * + * @see JsonHookPatchHook + */ + internal lateinit var hooks: JsonHookPatchHook + } + } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.kt index f2dec2a20..4b71bc2ab 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/BaseHookPatchPatch.kt @@ -4,13 +4,13 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.twitter.misc.hook.json.patch.JsonHookPatch -@DependsOn([JsonHookPatch::class]) abstract class BaseHookPatchPatch(private val hookClassDescriptor: String) : BytecodePatch() { override fun execute(context: BytecodeContext) = try { - PatchResultSuccess().also { JsonHookPatch.Hook(context, hookClassDescriptor).add() } + JsonHookPatch.hooks.addHook(JsonHookPatch.Hook(context, hookClassDescriptor)) + + PatchResultSuccess() } catch (ex: Exception) { PatchResultError(ex) } diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/annotations/HideAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/annotations/HideAdsCompatibility.kt index cdfab469e..d44fa95e0 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/annotations/HideAdsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/annotations/HideAdsCompatibility.kt @@ -3,10 +3,6 @@ package app.revanced.patches.twitter.misc.hook.patch.ads.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.twitter.android" - )] -) +@Compatibility([Package("com.twitter.android")]) @Target(AnnotationTarget.CLASS) internal annotation class HideAdsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/patch/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/patch/HideAdsPatch.kt index 6273a26d8..36b546014 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/patch/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/ads/patch/HideAdsPatch.kt @@ -15,8 +15,4 @@ import app.revanced.patches.twitter.misc.hook.patch.ads.annotations.HideAdsCompa @Description("Hides ads.") @HideAdsCompatibility @Version("0.0.1") -class HideAdsPatch : BaseHookPatchPatch(HOOK_CLASS_DESCRIPTOR) { - private companion object { - const val HOOK_CLASS_DESCRIPTOR = "Lapp/revanced/twitter/patches/hook/patch/ads/AdsHook;" - } -} \ No newline at end of file +class HideAdsPatch : BaseHookPatchPatch("Lapp/revanced/twitter/patches/hook/patch/ads/AdsHook;") \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/annotations/HideRecommendedUsersCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/annotations/HideRecommendedUsersCompatibility.kt index cac83ff82..196482e91 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/annotations/HideRecommendedUsersCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/annotations/HideRecommendedUsersCompatibility.kt @@ -3,10 +3,6 @@ package app.revanced.patches.twitter.misc.hook.patch.recommendation.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.twitter.android" - )] -) +@Compatibility([Package("com.twitter.android")]) @Target(AnnotationTarget.CLASS) internal annotation class HideRecommendedUsersCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/patch/HideRecommendedUsersPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/patch/HideRecommendedUsersPatch.kt index a6ea294fb..d38ab4893 100644 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/patch/HideRecommendedUsersPatch.kt +++ b/src/main/kotlin/app/revanced/patches/twitter/misc/hook/patch/recommendation/patch/HideRecommendedUsersPatch.kt @@ -15,9 +15,6 @@ import app.revanced.patches.twitter.misc.hook.patch.recommendation.annotations.H @Description("Hides recommended users.") @HideRecommendedUsersCompatibility @Version("0.0.1") -class HideRecommendedUsersPatch : BaseHookPatchPatch(HOOK_CLASS_DESCRIPTOR) { - private companion object { - const val HOOK_CLASS_DESCRIPTOR = - "Lapp/revanced/twitter/patches/hook/patch/recommendation/RecommendedUsersHook;" - } -} \ No newline at end of file +class HideRecommendedUsersPatch : BaseHookPatchPatch( + "Lapp/revanced/twitter/patches/hook/patch/recommendation/RecommendedUsersHook;" +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/vsco/misc/pro/fingerprints/RevCatSubscriptionFingerprint.kt b/src/main/kotlin/app/revanced/patches/vsco/misc/pro/fingerprints/RevCatSubscriptionFingerprint.kt new file mode 100644 index 000000000..871b6dcf0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/vsco/misc/pro/fingerprints/RevCatSubscriptionFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.vsco.misc.pro.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object RevCatSubscriptionFingerprint : MethodFingerprint( + returnType = "V", + strings = listOf("use_debug_subscription_settings"), + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("/RevCatSubscriptionSettingsRepository;") + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/vsco/misc/pro/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/vsco/misc/pro/patch/UnlockProPatch.kt new file mode 100644 index 000000000..1b428ba4b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/vsco/misc/pro/patch/UnlockProPatch.kt @@ -0,0 +1,35 @@ +package app.revanced.patches.vsco.misc.pro.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.* +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.vsco.misc.pro.fingerprints.RevCatSubscriptionFingerprint + + +@Patch +@Name("unlock-pro") +@Description("Unlocks pro features.") +@Compatibility([Package("com.vsco.cam")]) +@Version("0.0.1") +class UnlockProPatch : BytecodePatch( + listOf(RevCatSubscriptionFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + RevCatSubscriptionFingerprint.result?.mutableMethod?.apply { + // Set isSubscribed to true. + addInstructions( + 0, + """ + const p1, 0x1 + """ + ) + } ?: return RevCatSubscriptionFingerprint.toErrorResult() + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt index a0eb98d7e..31f02ab5e 100644 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt @@ -2,7 +2,7 @@ package app.revanced.patches.warnwetter.misc.promocode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PromoCodeUnlockFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("PromoTokenVerification;") && methodDef.name == "isValid" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt b/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt index 230f83a1e..353aa6a4e 100644 --- a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object CheckProFingerprint : MethodFingerprint( "I", - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("RawUserData;") && methodDef.name == "isPro" } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt deleted file mode 100644 index 65931d8c9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.patches.youtube.ad.general.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class GeneralAdsCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt new file mode 100644 index 000000000..798560a76 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/HideAdsCompatibility.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.youtube.ad.general.annotation + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideAdsCompatibility + diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/fingerprints/ReelConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/fingerprints/ReelConstructorFingerprint.kt deleted file mode 100644 index b6140dcc3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/fingerprints/ReelConstructorFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.ad.general.bytecode.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object ReelConstructorFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.INVOKE_VIRTUAL - ), - customFingerprint = { method -> - method.implementation?.instructions?.any { - it.opcode == Opcode.CONST && (it as WideLiteralInstruction).wideLiteral == GeneralAdsResourcePatch.reelMultipleItemShelfId - } ?: false - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/HideAdsPatch.kt similarity index 55% rename from src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralAdsPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/HideAdsPatch.kt index 9bcc728a4..4d907a659 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/HideAdsPatch.kt @@ -1,47 +1,32 @@ package app.revanced.patches.youtube.ad.general.bytecode.patch import app.revanced.extensions.findMutableMethodOf +import app.revanced.extensions.injectHideViewCall import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.instruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility -import app.revanced.patches.youtube.ad.general.bytecode.fingerprints.ReelConstructorFingerprint -import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch -import app.revanced.patches.youtube.misc.fix.backtoexitgesture.patch.FixBackToExitGesturePatch import app.revanced.patches.shared.misc.fix.verticalscroll.patch.VerticalScrollPatch -import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction +import app.revanced.patches.youtube.ad.general.annotation.HideAdsCompatibility +import app.revanced.patches.youtube.ad.general.resource.patch.HideAdsResourcePatch +import app.revanced.patches.youtube.misc.fix.backtoexitgesture.patch.FixBackToExitGesturePatch import org.jf.dexlib2.iface.instruction.formats.Instruction31i import org.jf.dexlib2.iface.instruction.formats.Instruction35c @Patch -@DependsOn([GeneralAdsResourcePatch::class, VerticalScrollPatch::class, FixBackToExitGesturePatch::class]) -@Name("general-ads") +@DependsOn([HideAdsResourcePatch::class, VerticalScrollPatch::class, FixBackToExitGesturePatch::class]) +@Name("hide-ads") @Description("Removes general ads.") -@GeneralAdsCompatibility +@HideAdsCompatibility @Version("0.0.1") -class GeneralAdsPatch : BytecodePatch( - listOf(ReelConstructorFingerprint) -) { +class HideAdsPatch : BytecodePatch() { override fun execute(context: BytecodeContext): PatchResult { - fun String.buildHideCall(viewRegister: Int) = "invoke-static { v$viewRegister }, " + - "Lapp/revanced/integrations/patches/GeneralAdsPatch;" + - "->" + - "$this(Landroid/view/View;)V" - - fun MutableMethod.injectHideCall(insertIndex: Int, viewRegister: Int, method: String) = - this.addInstruction(insertIndex, method.buildHideCall(viewRegister)) - context.classes.forEach { classDef -> classDef.methods.forEach { method -> with(method.implementation) { @@ -49,7 +34,7 @@ class GeneralAdsPatch : BytecodePatch( if (instruction.opcode != org.jf.dexlib2.Opcode.CONST) return@forEachIndexed // Instruction to store the id adAttribution into a register - if ((instruction as Instruction31i).wideLiteral != GeneralAdsResourcePatch.adAttributionId) + if ((instruction as Instruction31i).wideLiteral != HideAdsResourcePatch.adAttributionId) return@forEachIndexed val insertIndex = index + 1 @@ -64,29 +49,18 @@ class GeneralAdsPatch : BytecodePatch( context.proxy(classDef) .mutableClass .findMutableMethodOf(method) - .injectHideCall(insertIndex, viewRegister, "hideAdAttributionView") + .injectHideViewCall( + insertIndex, + viewRegister, + "Lapp/revanced/integrations/patches/components/AdsFilter;", + "hideAdAttributionView" + ) } } } } } - with( - ReelConstructorFingerprint.result - ?: return PatchResultError("Could not resolve fingerprint") - ) { - // iput-object v$viewRegister, ... - val insertIndex = this.scanResult.patternScanResult!!.startIndex + 2 - - with(this.mutableMethod) { - val viewRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA - - injectHideCall(insertIndex, viewRegister, "hideReelView") - } - - } - return PatchResultSuccess() } - } diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt deleted file mode 100644 index 4bcaecc3d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt +++ /dev/null @@ -1,303 +0,0 @@ -package app.revanced.patches.youtube.ad.general.resource.patch - -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.* -import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility -import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen - -@DependsOn( - dependencies = [ - LithoFilterPatch::class, - SettingsPatch::class, - ResourceMappingPatch::class - ] -) -@GeneralAdsCompatibility -@Version("0.0.1") -class GeneralAdsResourcePatch : ResourcePatch { - internal companion object { - var adAttributionId: Long = -1 - var reelMultipleItemShelfId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_adremover_separator", - StringResource("revanced_adremover_separator_title", "Hide gray separator"), - true, - StringResource("revanced_adremover_separator_summary_on", "Gray separators are hidden"), - StringResource("revanced_adremover_separator_summary_off", "Gray separators are shown") - ), - SwitchPreference( - "revanced_adremover_hide_channel_guidelines", - StringResource("revanced_adremover_hide_channel_guidelines_enabled_title", "Hide channel guidelines"), - true, - StringResource( - "revanced_adremover_hide_channel_guidelines_enabled_summary_on", - "Channel guidelines are hidden" - ), - StringResource( - "revanced_adremover_hide_channel_guidelines_enabled_summary_off", - "Channel guidelines are shown" - ) - ), - SwitchPreference( - "revanced_adremover_chapter_teaser", - StringResource( - "revanced_adremover_chapter_teaser_enabled_title", - "Hide chapter teaser under videos" - ), - true, - StringResource( - "revanced_adremover_chapter_teaser_enabled_summary_on", - "Chapter teasers are hidden" - ), - StringResource( - "revanced_adremover_chapter_teaser_enabled_summary_off", - "Chapter teasers are shown" - ) - ), - SwitchPreference( - "revanced_adremover_merchandise", - StringResource("revanced_adremover_merchandise_enabled_title", "Hide merchandise banners"), - true, - StringResource("revanced_adremover_merchandise_enabled_summary_on", "Merchandise banners are hidden"), - StringResource("revanced_adremover_merchandise_enabled_summary_off", "Merchandise banners are shown") - ), - SwitchPreference( - "revanced_adremover_community_posts_removal", - StringResource("revanced_adremover_community_posts_enabled_title", "Hide community posts"), - false, - StringResource("revanced_adremover_community_posts_enabled_summary_on", "Community posts are hidden"), - StringResource("revanced_adremover_community_posts_enabled_summary_off", "Community posts are shown") - ), - SwitchPreference( - "revanced_adremover_compact_banner_removal", - StringResource("revanced_adremover_compact_banner_enabled_title", "Hide compact banners"), - true, - StringResource("revanced_adremover_compact_banner_enabled_summary_on", "Compact banners are hidden"), - StringResource("revanced_adremover_compact_banner_enabled_summary_off", "Compact banners are shown") - ), - SwitchPreference( - "revanced_adremover_view_products", - StringResource("revanced_adremover_view_products_title", "Hide banner to view products"), - true, - StringResource("revanced_adremover_view_products_summary_on", "Banner is hidden"), - StringResource("revanced_adremover_view_products_summary_off", "Banner is shown") - ), - SwitchPreference( - "revanced_adremover_web_search_result", - StringResource("revanced_adremover_web_search_result_panel_title", "Hide web search results"), - true, - StringResource("revanced_adremover_web_search_result_summary_on", "Web search results are hidden"), - StringResource("revanced_adremover_web_search_result_summary_off", "Web search results are shown") - ), - SwitchPreference( - "revanced_adremover_movie", - StringResource("revanced_adremover_movie_enabled_title", "Hide movies section"), - true, - StringResource("revanced_adremover_movie_enabled_summary_on", "Movies section is hidden"), - StringResource("revanced_adremover_movie_enabled_summary_off", "Movies section is shown") - ), - SwitchPreference( - "revanced_adremover_feed_survey", - StringResource("revanced_adremover_feed_survey_enabled_title", "Hide feed surveys"), - true, - StringResource("revanced_adremover_feed_survey_enabled_summary_on", "Feed surveys are hidden"), - StringResource("revanced_adremover_feed_survey_enabled_summary_off", "Feed surveys are shown") - ), - SwitchPreference( - "revanced_adremover_shorts", - StringResource("revanced_adremover_shorts_enabled_title", "Hide shorts"), - true, - StringResource("revanced_adremover_shorts_enabled_summary_on", "Shorts are hidden"), - StringResource("revanced_adremover_shorts_enabled_summary_off", "Shorts are shown") - ), - SwitchPreference( - "revanced_adremover_community_guidelines", - StringResource("revanced_adremover_community_guidelines_enabled_title", "Hide community guidelines"), - true, - StringResource( - "revanced_adremover_community_guidelines_enabled_summary_on", - "Community guidelines are hidden" - ), - StringResource( - "revanced_adremover_community_guidelines_enabled_summary_off", - "Community guidelines are shown" - ) - ), - SwitchPreference( - "revanced_adremover_subscribers_community_guidelines_removal", - StringResource( - "revanced_adremover_subscribers_community_guidelines_enabled_title", - "Hide subscribers community guidelines" - ), - true, - StringResource( - "revanced_adremover_subscribers_community_guidelines_enabled_summary_on", - "Subscribers community guidelines are hidden" - ), - StringResource( - "revanced_adremover_subscribers_community_guidelines_enabled_summary_off", - "Subscribers community guidelines are shown" - ) - ), - SwitchPreference( - "revanced_adremover_channel_member_shelf_removal", - StringResource("revanced_adremover_channel_member_shelf_enabled_title", "Hide channel member shelf"), - true, - StringResource( - "revanced_adremover_channel_member_shelf_enabled_summary_on", - "Channel member shelf is hidden" - ), - StringResource( - "revanced_adremover_channel_member_shelf_enabled_summary_off", - "Channel member shelf is shown" - ) - ), - SwitchPreference( - "revanced_adremover_emergency_box_removal", - StringResource("revanced_adremover_emergency_box_enabled_title", "Hide emergency boxes"), - true, - StringResource("revanced_adremover_emergency_box_enabled_summary_on", "Emergency boxes are hidden"), - StringResource("revanced_adremover_emergency_box_enabled_summary_off", "Emergency boxes are shown") - ), - SwitchPreference( - "revanced_adremover_info_panel", - StringResource("revanced_adremover_info_panel_enabled_title", "Hide info panels"), - true, - StringResource("revanced_adremover_info_panel_enabled_summary_on", "Info panels are hidden"), - StringResource("revanced_adremover_info_panel_enabled_summary_off", "Info panels are shown") - ), - SwitchPreference( - "revanced_adremover_medical_panel", - StringResource("revanced_adremover_medical_panel_enabled_title", "Hide medical panels"), - true, - StringResource("revanced_adremover_medical_panel_enabled_summary_on", "Medical panels are hidden"), - StringResource("revanced_adremover_medical_panel_enabled_summary_off", "Medical panels are shown") - ), - SwitchPreference( - "revanced_hide_channel_bar", - StringResource("revanced_hide_channel_bar_title", "Hide channel bar"), - false, - StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"), - StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown") - ), - SwitchPreference( - "revanced_hide_quick_actions", - StringResource("revanced_hide_quick_actions_title", "Hide quick actions in fullscreen"), - false, - StringResource("revanced_hide_quick_actions_summary_on", "Quick actions are hidden"), - StringResource("revanced_hide_quick_actions_summary_off", "Quick actions are shown") - ), - SwitchPreference( - "revanced_hide_related_videos", - StringResource("revanced_hide_related_videos_title", "Hide related videos in quick actions"), - false, - StringResource("revanced_hide_related_videos_summary_on", "Related videos are hidden"), - StringResource("revanced_hide_related_videos_summary_off", "Related videos are shown") - ), - SwitchPreference( - "revanced_hide_image_shelf", - StringResource("revanced_hide_image_shelf", "Hide image shelf in search results"), - true, - StringResource("revanced_hide_image_shelf_summary_on", "Image shelf is hidden"), - StringResource("revanced_hide_image_shelf_summary_off", "Image shelf is shown") - ), - SwitchPreference( - "revanced_hide_audio_track_button", - StringResource("revanced_hide_audio_track_button_title", "Hide audio track button"), - false, - StringResource("revanced_hide_audio_track_button_on", "Audio track button is hidden"), - StringResource("revanced_hide_audio_track_button_off", "Audio track button is shown") - ) - ) - - PreferenceScreen.ADS.addPreferences( - SwitchPreference( - "revanced_adremover_ad_removal", - StringResource("revanced_adremover_ad_removal_enabled_title", "Hide general ads"), - true, - StringResource("revanced_adremover_ad_removal_enabled_summary_on", "General ads are hidden"), - StringResource("revanced_adremover_ad_removal_enabled_summary_off", "General ads are shown") - ), - SwitchPreference( - "revanced_adremover_buttoned", - StringResource("revanced_adremover_buttoned_enabled_title", "Hide buttoned ad"), - true, - StringResource("revanced_adremover_buttoned_enabled_summary_on", "Buttoned ads are hidden"), - StringResource("revanced_adremover_buttoned_enabled_summary_off", "Buttoned ads are shown") - ), - SwitchPreference( - "revanced_adremover_paid_content", - StringResource("revanced_adremover_paid_content_enabled_title", "Hide paid content"), - true, - StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"), - StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown") - ), - SwitchPreference( - "revanced_adremover_hide_latest_posts", - StringResource("revanced_adremover_hide_latest_posts_enabled_title", "Hide latest posts"), - true, - StringResource("revanced_adremover_hide_latest_posts_enabled_summary_on", "Latest posts are hidden"), - StringResource("revanced_adremover_hide_latest_posts_enabled_summary_off", "Latest posts are shown") - ), - SwitchPreference( - "revanced_adremover_self_sponsor", - StringResource("revanced_adremover_self_sponsor_enabled_title", "Hide self sponsored cards"), - true, - StringResource("revanced_adremover_self_sponsor_enabled_summary_on", "Self sponsored cards are hidden"), - StringResource("revanced_adremover_self_sponsor_enabled_summary_off", "Self sponsored cards are shown") - ), - PreferenceScreen( - "revanced_adremover_custom", - StringResource("revanced_adremover_custom_title", "Custom filter"), - listOf( - SwitchPreference( - "revanced_adremover_custom_enabled", - StringResource( - "revanced_adremover_custom_enabled_title", - "Enable custom filter" - ), - false, - StringResource( - "revanced_adremover_custom_enabled_summary_on", - "Custom filter is enabled" - ), - StringResource( - "revanced_adremover_custom_enabled_summary_off", - "Custom filter is disabled" - ) - ), - // TODO: This should be a dynamic ListPreference, which does not exist yet - TextPreference( - "revanced_adremover_custom_strings", - StringResource("revanced_adremover_custom_strings_title", "Custom filter"), - InputType.STRING, - "", - StringResource( - "revanced_adremover_custom_strings_summary", - "Filter components by their name separated by a comma" - ) - ) - ) - ) - ) - - fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id - - adAttributionId = "ad_attribution".getId() - reelMultipleItemShelfId = "reel_multiple_items_shelf".getId() - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/HideAdsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/HideAdsResourcePatch.kt new file mode 100644 index 000000000..4491d4326 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/HideAdsResourcePatch.kt @@ -0,0 +1,264 @@ +package app.revanced.patches.youtube.ad.general.resource.patch + +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.* +import app.revanced.patches.youtube.ad.general.annotation.HideAdsCompatibility +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch.PreferenceScreen + +@DependsOn( + dependencies = [ + LithoFilterPatch::class, + SettingsPatch::class, + ResourceMappingPatch::class + ] +) +@HideAdsCompatibility +@Version("0.0.1") +class HideAdsResourcePatch : ResourcePatch { + + override fun execute(context: ResourceContext): PatchResult { + PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_hide_gray_separator", + StringResource("revanced_hide_gray_separator_title", "Hide gray separator"), + StringResource("revanced_hide_gray_separator_summary_on", "Gray separators are hidden"), + StringResource("revanced_hide_gray_separator_summary_off", "Gray separators are shown") + ), + SwitchPreference( + "revanced_hide_channel_guidelines", + StringResource("revanced_hide_channel_guidelines_title", "Hide channel guidelines"), + StringResource( + "revanced_hide_channel_guidelines_summary_on", + "Channel guidelines are hidden" + ), + StringResource( + "revanced_hide_channel_guidelines_summary_off", + "Channel guidelines are shown" + ) + ), + SwitchPreference( + "revanced_hide_chapter_teaser", + StringResource( + "revanced_hide_chapter_teaser_title", + "Hide chapter teaser under videos" + ), + StringResource( + "revanced_hide_chapter_teaser_summary_on", + "Chapter teasers are hidden" + ), + StringResource( + "revanced_hide_chapter_teaser_summary_off", + "Chapter teasers are shown" + ) + ), + SwitchPreference( + "revanced_hide_merchandise_banners", + StringResource("revanced_hide_merchandise_banners_title", "Hide merchandise banners"), + StringResource("revanced_hide_merchandise_banners_summary_on", "Merchandise banners are hidden"), + StringResource("revanced_hide_merchandise_banners_summary_off", "Merchandise banners are shown") + ), + SwitchPreference( + "revanced_hide_community_posts", + StringResource("revanced_hide_community_posts_title", "Hide community posts"), + StringResource("revanced_hide_community_posts_summary_on", "Community posts are hidden"), + StringResource("revanced_hide_community_posts_summary_off", "Community posts are shown") + ), + SwitchPreference( + "revanced_hide_compact_banner", + StringResource("revanced_hide_compact_banner_title", "Hide compact banners"), + StringResource("revanced_hide_compact_banner_summary_on", "Compact banners are hidden"), + StringResource("revanced_hide_compact_banner_summary_off", "Compact banners are shown") + ), + SwitchPreference( + "revanced_hide_products_banner", + StringResource("revanced_hide_products_banner_title", "Hide banner to view products"), + StringResource("revanced_hide_products_banner_summary_on", "Banner is hidden"), + StringResource("revanced_hide_products_banner_summary_off", "Banner is shown") + ), + SwitchPreference( + "revanced_hide_web_search_results", + StringResource("revanced_hide_web_search_results_title", "Hide web search results"), + StringResource("revanced_hide_web_search_results_summary_on", "Web search results are hidden"), + StringResource("revanced_hide_web_search_results_summary_off", "Web search results are shown") + ), + SwitchPreference( + "revanced_hide_movies_section", + StringResource("revanced_hide_movies_section_title", "Hide movies section"), + StringResource("revanced_hide_movies_section_summary_on", "Movies section is hidden"), + StringResource("revanced_hide_movies_section_summary_off", "Movies section is shown") + ), + SwitchPreference( + "revanced_hide_feed_survey", + StringResource("revanced_hide_feed_survey_title", "Hide feed surveys"), + StringResource("revanced_hide_feed_survey_summary_on", "Feed surveys are hidden"), + StringResource("revanced_hide_feed_survey_summary_off", "Feed surveys are shown") + ), + SwitchPreference( + "revanced_hide_community_guidelines", + StringResource("revanced_hide_community_guidelines_title", "Hide community guidelines"), + StringResource( + "revanced_hide_community_guidelines_summary_on", + "Community guidelines are hidden" + ), + StringResource( + "revanced_hide_community_guidelines_summary_off", + "Community guidelines are shown" + ) + ), + SwitchPreference( + "revanced_hide_subscribers_community_guidelines", + StringResource( + "revanced_hide_subscribers_community_guidelines_title", + "Hide subscribers community guidelines" + ), + StringResource( + "revanced_hide_subscribers_community_guidelines_summary_on", + "Subscribers community guidelines are hidden" + ), + StringResource( + "revanced_hide_subscribers_community_guidelines_summary_off", + "Subscribers community guidelines are shown" + ) + ), + SwitchPreference( + "revanced_hide_channel_member_shelf", + StringResource("revanced_hide_channel_member_shelf_title", "Hide channel member shelf"), + StringResource( + "revanced_hide_channel_member_shelf_summary_on", + "Channel member shelf is hidden" + ), + StringResource( + "revanced_hide_channel_member_shelf_summary_off", + "Channel member shelf is shown" + ) + ), + SwitchPreference( + "revanced_hide_emergency_box", + StringResource("revanced_hide_emergency_box_title", "Hide emergency boxes"), + StringResource("revanced_hide_emergency_box_summary_on", "Emergency boxes are hidden"), + StringResource("revanced_hide_emergency_box_summary_off", "Emergency boxes are shown") + ), + SwitchPreference( + "revanced_hide_info_panels", + StringResource("revanced_hide_info_panels_title", "Hide info panels"), + StringResource("revanced_hide_info_panels_summary_on", "Info panels are hidden"), + StringResource("revanced_hide_info_panels_summary_off", "Info panels are shown") + ), + SwitchPreference( + "revanced_hide_medical_panels", + StringResource("revanced_hide_medical_panels_title", "Hide medical panels"), + StringResource("revanced_hide_medical_panels_summary_on", "Medical panels are hidden"), + StringResource("revanced_hide_medical_panels_summary_off", "Medical panels are shown") + ), + SwitchPreference( + "revanced_hide_channel_bar", + StringResource("revanced_hide_channel_bar_title", "Hide channel bar"), + StringResource("revanced_hide_channel_bar_summary_on", "Channel bar is hidden"), + StringResource("revanced_hide_channel_bar_summary_off", "Channel bar is shown") + ), + SwitchPreference( + "revanced_hide_quick_actions", + StringResource("revanced_hide_quick_actions_title", "Hide quick actions in fullscreen"), + StringResource("revanced_hide_quick_actions_summary_on", "Quick actions are hidden"), + StringResource("revanced_hide_quick_actions_summary_off", "Quick actions are shown") + ), + SwitchPreference( + "revanced_hide_related_videos", + StringResource("revanced_hide_related_videos_title", "Hide related videos in quick actions"), + StringResource("revanced_hide_related_videos_summary_on", "Related videos are hidden"), + StringResource("revanced_hide_related_videos_summary_off", "Related videos are shown") + ), + SwitchPreference( + "revanced_hide_image_shelf", + StringResource("revanced_hide_image_shelf", "Hide image shelf in search results"), + StringResource("revanced_hide_image_shelf_summary_on", "Image shelf is hidden"), + StringResource("revanced_hide_image_shelf_summary_off", "Image shelf is shown") + ), + SwitchPreference( + "revanced_hide_audio_track_button", + StringResource("revanced_hide_audio_track_button_title", "Hide audio track button"), + StringResource("revanced_hide_audio_track_button_on", "Audio track button is hidden"), + StringResource("revanced_hide_audio_track_button_off", "Audio track button is shown") + ), + SwitchPreference( + "revanced_hide_latest_posts_ads", + StringResource("revanced_hide_latest_posts_ads_title", "Hide latest posts"), + StringResource("revanced_hide_latest_posts_ads_summary_on", "Latest posts are hidden"), + StringResource("revanced_hide_latest_posts_ads_summary_off", "Latest posts are shown") + ), + ) + + PreferenceScreen.ADS.addPreferences( + SwitchPreference( + "revanced_hide_general_ads", + StringResource("revanced_hide_general_ads_title", "Hide general ads"), + StringResource("revanced_hide_general_ads_summary_on", "General ads are hidden"), + StringResource("revanced_hide_general_ads_summary_off", "General ads are shown") + ), + SwitchPreference( + "revanced_hide_buttoned_ads", + StringResource("revanced_hide_buttoned_ads_title", "Hide buttoned ad"), + StringResource("revanced_hide_buttoned_ads_summary_on", "Buttoned ads are hidden"), + StringResource("revanced_hide_buttoned_ads_summary_off", "Buttoned ads are shown") + ), + SwitchPreference( + "revanced_hide_paid_content_ads", + StringResource("revanced_hide_paid_content_ads_title", "Hide paid content"), + StringResource("revanced_hide_paid_content_ads_summary_on", "Paid content is hidden"), + StringResource("revanced_hide_paid_content_ads_summary_off", "Paid content is shown") + ), + SwitchPreference( + "revanced_hide_self_sponsor_ads", + StringResource("revanced_hide_self_sponsor_ads_title", "Hide self sponsored cards"), + StringResource("revanced_hide_self_sponsor_ads_summary_on", "Self sponsored cards are hidden"), + StringResource("revanced_hide_self_sponsor_ads_summary_off", "Self sponsored cards are shown") + ), + PreferenceScreen( + "revanced_custom_filter_preference_screen", + StringResource("revanced_custom_filter_preference_screen_title", "Custom filter"), + listOf( + SwitchPreference( + "revanced_custom_filter", + StringResource( + "revanced_custom_filter_title", + "Enable custom filter" + ), + StringResource( + "revanced_custom_filter_summary_on", + "Custom filter is enabled" + ), + StringResource( + "revanced_custom_filter_summary_off", + "Custom filter is disabled" + ) + ), + // TODO: This should be a dynamic ListPreference, which does not exist yet + TextPreference( + "revanced_custom_filter_strings", + StringResource("revanced_custom_filter_strings_title", "Custom filter"), + StringResource( + "revanced_custom_filter_strings_summary", + "Filter components by their name separated by a comma" + ) + ) + ) + ) + ) + + adAttributionId = ResourceMappingPatch.resourceMappings.single { it.name == "ad_attribution" }.id + + return PatchResultSuccess() + } + + internal companion object { + var adAttributionId: Long = -1 + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt index a6e9279e8..6713227a1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt @@ -3,23 +3,7 @@ package app.revanced.patches.youtube.ad.video.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class VideoAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt index 10e14d39d..000b4b54b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt @@ -33,11 +33,10 @@ class VideoAdsPatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.ADS.addPreferences( SwitchPreference( - "revanced_video_ads_removal", - StringResource("revanced_video_ads_removal_title", "Hide video ads"), - true, - StringResource("revanced_video_ads_removal_summary_on", "Video ads are hidden"), - StringResource("revanced_video_ads_removal_summary_off", "Video ads are shown") + "revanced_hide_video_ads", + StringResource("revanced_hide_video_ads_title", "Hide video ads"), + StringResource("revanced_hide_video_ads_summary_on", "Video ads are hidden"), + StringResource("revanced_hide_video_ads_summary_off", "Video ads are shown") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt index df42c40f2..fc46729a4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/annotation/CopyVideoUrlCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.interaction.copyvideourl.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class CopyVideoUrlCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/bytecode/patch/CopyVideoUrlBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/bytecode/patch/CopyVideoUrlBytecodePatch.kt index c015612a4..46823e409 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/bytecode/patch/CopyVideoUrlBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/bytecode/patch/CopyVideoUrlBytecodePatch.kt @@ -12,7 +12,7 @@ import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.youtube.interaction.copyvideourl.annotation.CopyVideoUrlCompatibility import app.revanced.patches.youtube.interaction.copyvideourl.resource.patch.CopyVideoUrlResourcePatch import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch +import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch @Patch @Name("copy-video-url") @@ -26,8 +26,7 @@ import app.revanced.patches.youtube.misc.video.information.patch.VideoInformatio @Version("0.0.1") class CopyVideoUrlBytecodePatch : BytecodePatch() { private companion object { - const val INTEGRATIONS_PACKAGE = "Lapp/revanced/integrations" - const val INTEGRATIONS_PLAYER_PACKAGE = "$INTEGRATIONS_PACKAGE/videoplayer" + const val INTEGRATIONS_PLAYER_PACKAGE = "Lapp/revanced/integrations/videoplayer" val BUTTONS_DESCRIPTORS = listOf( "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlButton;", "$INTEGRATIONS_PLAYER_PACKAGE/CopyVideoUrlTimestampButton;" @@ -38,10 +37,8 @@ class CopyVideoUrlBytecodePatch : BytecodePatch() { // Initialize buttons and inject visibility control BUTTONS_DESCRIPTORS.forEach { descriptor -> - val initializeButtonDescriptor = "$descriptor->initializeButton(Ljava/lang/Object;)V" - val visibilityDescriptor = "$descriptor->changeVisibility(Z)V" - PlayerControlsBytecodePatch.initializeControl(initializeButtonDescriptor) - PlayerControlsBytecodePatch.injectVisibilityCheckCall(visibilityDescriptor) + PlayerControlsBytecodePatch.initializeControl("$descriptor->initializeButton(Landroid/view/View;)V") + PlayerControlsBytecodePatch.injectVisibilityCheckCall("$descriptor->changeVisibility(Z)V") } return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/resource/patch/CopyVideoUrlResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/resource/patch/CopyVideoUrlResourcePatch.kt index 6e60282cd..3d0124fd4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/resource/patch/CopyVideoUrlResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/resource/patch/CopyVideoUrlResourcePatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.interaction.copyvideourl.resource.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.ResourceContext @@ -11,40 +10,36 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.interaction.copyvideourl.annotation.CopyVideoUrlCompatibility import app.revanced.patches.youtube.misc.playercontrols.resource.patch.BottomControlsResourcePatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.util.resources.ResourceUtils import app.revanced.util.resources.ResourceUtils.copyResources +import app.revanced.util.resources.ResourceUtils.mergeStrings @Name("copy-video-url-resource") -@Description("Makes necessary changes to resources for copy video link buttons.") @DependsOn([BottomControlsResourcePatch::class, SettingsPatch::class]) -@CopyVideoUrlCompatibility @Version("0.0.1") class CopyVideoUrlResourcePatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( PreferenceScreen( - "revanced_copy_video_url", - StringResource("revanced_copy_video_url_title", "Copy video URL settings"), + "revanced_copy_video_url_preference_screen", + StringResource("revanced_copy_video_url_preference_screen_title", "Copy video URL settings"), listOf( SwitchPreference( - "revanced_copy_video_url_enabled", - StringResource("revanced_copy_video_url_enabled_title", "Show copy video URL button"), - true, - StringResource("revanced_copy_video_url_enabled_summary_on", "Button is shown, click to copy video URL without timestamp"), - StringResource("revanced_copy_video_url_enabled_summary_off", "Button is not shown") + "revanced_copy_video_url", + StringResource("revanced_copy_video_url_title", "Show copy video URL button"), + StringResource("revanced_copy_video_url_summary_on", "Button is shown. Tap to copy video URL. Tap and hold to copy video URL with timestamp"), + StringResource("revanced_copy_video_url_summary_off", "Button is not shown") ), SwitchPreference( - "revanced_copy_video_url_timestamp_enabled", - StringResource("revanced_copy_video_url_timestamp_enabled_title", "Show copy timestamp URL button"), - true, - StringResource("revanced_copy_video_url_timestamp_enabled_summary_on", "Button is shown, click to copy video URL with timestamp"), - StringResource("revanced_copy_video_url_timestamp_enabled_summary_off", "Button is not shown") + "revanced_copy_video_url_timestamp", + StringResource("revanced_copy_video_url_timestamp_title", "Show copy timestamp URL button"), + StringResource("revanced_copy_video_url_timestamp_summary_on", "Button is shown. Tap to copy video URL with timestamp. Tap and hold to copy video without timestamp"), + StringResource("revanced_copy_video_url_timestamp_summary_off", "Button is not shown") ) ), - StringResource("revanced_copy_video_url_summary", "Settings related to copy URL buttons in video player") + StringResource("revanced_copy_video_url_preference_screen_summary", "Settings related to copy URL buttons in video player") ) ) @@ -54,6 +49,9 @@ class CopyVideoUrlResourcePatch : ResourcePatch { "revanced_yt_copy_timestamp.xml" )) + // merge strings + context.mergeStrings("copyvideourl/host/values/strings.xml") + BottomControlsResourcePatch.addControls("copyvideourl/host/layout/${BottomControlsResourcePatch.TARGET_RESOURCE_NAME}") return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt index 9f84d2ab6..5e8525309 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt @@ -3,23 +3,7 @@ package app.revanced.patches.youtube.interaction.downloads.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class DownloadsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt index 244dbeadf..d296b396f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt @@ -12,32 +12,33 @@ import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility import app.revanced.patches.youtube.interaction.downloads.resource.patch.DownloadsResourcePatch import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch +import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch @Patch @Name("downloads") @DependsOn([DownloadsResourcePatch::class, PlayerControlsBytecodePatch::class, VideoInformationPatch::class]) -@Description("Enables downloading music and videos from YouTube.") +@Description("Adds a download button to the YouTube video player.") @DownloadsCompatibility @Version("0.0.1") class DownloadsBytecodePatch : BytecodePatch() { - override fun execute(context: BytecodeContext): PatchResult { - val integrationsPackage = "app/revanced/integrations" - val classDescriptor = "L$integrationsPackage/videoplayer/DownloadButton;" + private companion object { + const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/videoplayer/DownloadButton;" + } + override fun execute(context: BytecodeContext): PatchResult { /* initialize the control */ - val initializeDownloadsDescriptor = "$classDescriptor->initializeButton(Ljava/lang/Object;)V" - PlayerControlsBytecodePatch.initializeControl(initializeDownloadsDescriptor) + PlayerControlsBytecodePatch.initializeControl( + "$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V") /* add code to change the visibility of the control */ - val changeVisibilityDescriptor = "$classDescriptor->changeVisibility(Z)V" - PlayerControlsBytecodePatch.injectVisibilityCheckCall(changeVisibilityDescriptor) + PlayerControlsBytecodePatch.injectVisibilityCheckCall( + "$BUTTON_DESCRIPTOR->changeVisibility(Z)V") return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt index f628f4d0c..4ab4a883c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.interaction.downloads.resource.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.ResourceContext @@ -9,7 +8,6 @@ import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.shared.settings.preference.impl.* -import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility import app.revanced.patches.youtube.misc.playercontrols.resource.patch.BottomControlsResourcePatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.util.resources.ResourceUtils @@ -18,32 +16,28 @@ import app.revanced.util.resources.ResourceUtils.mergeStrings @Name("downloads-resource-patch") @DependsOn([BottomControlsResourcePatch::class, SettingsPatch::class]) -@Description("Makes necessary changes to resources for the download button.") -@DownloadsCompatibility @Version("0.0.1") class DownloadsResourcePatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( PreferenceScreen( - "revanced_downloads", - StringResource("revanced_downloads_title", "Download settings"), + "revanced_external_downloader_preference_screen", + StringResource("revanced_external_downloader_preference_screen_title", "Download settings"), listOf( SwitchPreference( - "revanced_downloads_enabled", - StringResource("revanced_downloads_enabled_title", "Show download button"), - true, - StringResource("revanced_downloads_enabled_summary_on", "Download button is shown"), - StringResource("revanced_downloads_enabled_summary_off", "Download button is not shown") + "revanced_external_downloader", + StringResource("revanced_external_downloader_title", "Show download button"), + StringResource("revanced_external_downloader_summary_on", "Download button is shown"), + StringResource("revanced_external_downloader_summary_off", "Download button is not shown") ), TextPreference( - "revanced_downloads_package_name", - StringResource("revanced_downloads_package_name_title", "Downloader package name"), - InputType.STRING, - "org.schabi.newpipe" /* NewPipe */, - StringResource("revanced_downloads_package_name_summary", "Package name of the downloader app such as NewPipe\\'s or PowerTube\\'s") + "revanced_external_downloader_name", + StringResource("revanced_external_downloader_name_title", "Downloader package name"), + StringResource("revanced_external_downloader_name_summary", "Package name of the downloader app such as NewPipe\\'s or PowerTube\\'s"), + InputType.TEXT ) ), - StringResource("revanced_downloads_summary", "Settings related to downloads") + StringResource("revanced_external_downloader_preference_screen_summary", "Settings related to downloads") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt index b0aef8f99..56a7b6893 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt @@ -3,23 +3,7 @@ package app.revanced.patches.youtube.interaction.seekbar.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class SeekbarTappingCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/AccessibilityPlayerProgressTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/AccessibilityPlayerProgressTimeFingerprint.kt new file mode 100644 index 000000000..d6d0653af --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/AccessibilityPlayerProgressTimeFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.interaction.seekbar.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.interaction.seekbar.patch.EnableSeekbarTappingResourcePatch +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + + +object AccessibilityPlayerProgressTimeFingerprint : MethodFingerprint( + returnType = "L", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { instruction -> + if (instruction.opcode != Opcode.CONST) return@any false + + val wideLiteral = (instruction as WideLiteralInstruction).wideLiteral + + EnableSeekbarTappingResourcePatch.accessibilityPlayerProgressTime == wideLiteral + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt index 94d6b2cef..3c8f3ed0b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt @@ -1,34 +1,34 @@ package app.revanced.patches.youtube.interaction.seekbar.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction -@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object SeekbarTappingFingerprint : MethodFingerprint( - "Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_WIDE, - Opcode.IGET, - Opcode.IGET_OBJECT, - Opcode.IGET, - Opcode.DIV_INT_2ADDR, - Opcode.ADD_INT, - Opcode.SUB_INT_2ADDR, - Opcode.INT_TO_FLOAT, - Opcode.CMPG_FLOAT, - Opcode.IF_GTZ, - Opcode.INT_TO_FLOAT, - Opcode.CMPG_FLOAT, - Opcode.IF_GTZ, - Opcode.CONST_4, - Opcode.INVOKE_INTERFACE, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, + returnType = "Z", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( Opcode.IPUT_OBJECT, - Opcode.INVOKE_VIRTUAL - ) + Opcode.INVOKE_VIRTUAL, + // Insert seekbar tapping instructions here. + Opcode.RETURN, + Opcode.INVOKE_VIRTUAL, + ), + customFingerprint = custom@{ methodDef, _ -> + if (methodDef.name != "onTouchEvent") return@custom false + + methodDef.implementation!!.instructions.any { instruction -> + if (instruction.opcode != Opcode.CONST) return@any false + + val literal = (instruction as NarrowLiteralInstruction).narrowLiteral + + // onTouchEvent method contains a CONST instruction + // with this literal making it unique with the rest of the properties of this fingerprint. + literal == Integer.MAX_VALUE + } + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingParentFingerprint.kt deleted file mode 100644 index 20f83effb..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingParentFingerprint.kt +++ /dev/null @@ -1,44 +0,0 @@ -package app.revanced.patches.youtube.interaction.seekbar.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - - -@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. -object SeekbarTappingParentFingerprint : MethodFingerprint( - "L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_4, - Opcode.NEW_ARRAY, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_WIDE, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_4, - Opcode.APUT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_WIDE, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_4, - Opcode.APUT_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.RETURN_OBJECT - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt index fed792408..b9d0dc097 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt @@ -1,110 +1,95 @@ package app.revanced.patches.youtube.interaction.seekbar.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility +import app.revanced.patches.youtube.interaction.seekbar.fingerprints.AccessibilityPlayerProgressTimeFingerprint import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingFingerprint -import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingParentFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.instruction.BuilderInstruction21t import org.jf.dexlib2.iface.Method -import org.jf.dexlib2.iface.instruction.formats.Instruction11n +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction import org.jf.dexlib2.iface.instruction.formats.Instruction35c @Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) +@DependsOn([IntegrationsPatch::class, EnableSeekbarTappingResourcePatch::class]) @Name("seekbar-tapping") @Description("Enables tap-to-seek on the seekbar of the video player.") @SeekbarTappingCompatibility @Version("0.0.1") class EnableSeekbarTappingPatch : BytecodePatch( - listOf( - SeekbarTappingParentFingerprint, SeekbarTappingFingerprint - ) + listOf(AccessibilityPlayerProgressTimeFingerprint, SeekbarTappingFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - SwitchPreference( - "revanced_enable_tap_seeking", - StringResource("revanced_seekbar_tapping_enabled_title", "Enable seekbar tapping"), - true, - StringResource("revanced_seekbar_tapping_summary_on", "Seekbar tapping is enabled"), - StringResource("revanced_seekbar_tapping_summary_off", "Seekbar tapping is disabled") - ) - ) + // Find the required methods to tap the seekbar. + val seekbarTappingMethods = + AccessibilityPlayerProgressTimeFingerprint.result?.classDef?.methods?.let { methods -> + buildMap { + // find the methods which tap the seekbar + methods.forEach { method -> + if (method.implementation == null) return@forEach - var result = SeekbarTappingParentFingerprint.result!! + val instructions = method.implementation!!.instructions - val tapSeekMethods = mutableMapOf<String, Method>() + // The method has more than 7 instructions. + if (instructions.count() < 7) return@forEach - // find the methods which tap the seekbar - for (it in result.classDef.methods) { - if (it.implementation == null) continue + // The 7th instruction has the opcode CONST_4. + val instruction = instructions.elementAt(6) + if (instruction.opcode != Opcode.CONST_4) return@forEach - val instructions = it.implementation!!.instructions - // here we make sure we actually find the method because it has more than 7 instructions - if (instructions.count() < 7) continue + // the literal for this instruction has to be either 1 or 2. + val literal = (instruction as NarrowLiteralInstruction).narrowLiteral - // we know that the 7th instruction has the opcode CONST_4 - val instruction = instructions.elementAt(6) - if (instruction.opcode != Opcode.CONST_4) continue + // Based on the literal, determine which method is which. + if (literal == 1) this["P"] = method + if (literal == 2) this["O"] = method + } + } + } - // the literal for this instruction has to be either 1 or 2 - val literal = (instruction as Instruction11n).narrowLiteral + seekbarTappingMethods ?: return AccessibilityPlayerProgressTimeFingerprint.toErrorResult() - // method founds - if (literal == 1) tapSeekMethods["P"] = it - if (literal == 2) tapSeekMethods["O"] = it - } + SeekbarTappingFingerprint.result?.let { + val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1 - // replace map because we don't need the upper one anymore - result = SeekbarTappingFingerprint.result!! + it.mutableMethod.apply { + val thisInstanceRegister = instruction<Instruction35c>(insertIndex - 1).registerC - val implementation = result.mutableMethod.implementation!! + val freeRegister = 0 + val xAxisRegister = 2 - // if tap-seeking is enabled, do not invoke the two methods below - val pMethod = tapSeekMethods["P"]!! - val oMethod = tapSeekMethods["O"]!! + val pMethod = seekbarTappingMethods["P"]!! + val oMethod = seekbarTappingMethods["O"]!! - val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1 + fun Method.toInvokeInstructionString() = + "invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $definingClass->$name(I)V" - // get the required register - val instruction = implementation.instructions[insertIndex - 1] - if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return PatchResultError("Could not find the correct register") - val register = (instruction as Instruction35c).registerC + addInstructions( + insertIndex, + """ + invoke-static { }, Lapp/revanced/integrations/patches/SeekbarTappingPatch;->seekbarTappingEnabled()Z + move-result v$freeRegister + if-eqz v$freeRegister, :disabled + ${oMethod.toInvokeInstructionString()} + ${pMethod.toInvokeInstructionString()} + """, + listOf(ExternalLabel("disabled", instruction(insertIndex))) + ) + } + } ?: return SeekbarTappingFingerprint.toErrorResult() - val elseLabel = implementation.newLabelForIndex(insertIndex) - // the instructions are written in reverse order. - result.mutableMethod.addInstructions( - insertIndex, """ - invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V - invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V - """ - ) - - // if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label - implementation.addInstruction( - insertIndex, BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel) - ) - result.mutableMethod.addInstructions( - insertIndex, """ - invoke-static { }, Lapp/revanced/integrations/patches/SeekbarTappingPatch;->isTapSeekingEnabled()Z - move-result v0 - """ - ) return PatchResultSuccess() } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingResourcePatch.kt new file mode 100644 index 000000000..d2281ad27 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingResourcePatch.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.youtube.interaction.seekbar.patch + +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch + +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +@Version("0.0.1") +class EnableSeekbarTappingResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( + SwitchPreference( + "revanced_seekbar_tapping", + StringResource("revanced_seekbar_tapping_title", "Enable seekbar tapping"), + StringResource("revanced_seekbar_tapping_summary_on", "Seekbar tapping is enabled"), + StringResource("revanced_seekbar_tapping_summary_off", "Seekbar tapping is disabled") + ) + ) + + accessibilityPlayerProgressTime = ResourceMappingPatch.resourceMappings.find { + it.name == "accessibility_player_progress_time" + }?.id ?: return PatchResultError("Failed to find required resource") + + return PatchResultSuccess() + } + + internal companion object { + var accessibilityPlayerProgressTime = -1L + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt index cb86f6017..feaa5effc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.interaction.swipecontrols.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class SwipeControlsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt index 25e3ada23..368ba1fdd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.youtube.interaction.swipecontrols.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SwipeControlsHostActivityFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lapp/revanced/integrations/swipecontrols/SwipeControlsHostActivity;" && methodDef.name == "<init>" } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt index 01cfffd5d..ee1758e75 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt @@ -7,92 +7,80 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.shared.settings.preference.impl.TextPreference -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.youtube.interaction.swipecontrols.annotation.SwipeControlsCompatibility +import app.revanced.patches.shared.settings.preference.impl.* import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.util.resources.ResourceUtils import app.revanced.util.resources.ResourceUtils.copyResources @Name("swipe-controls-resource-patch") @DependsOn([SettingsPatch::class]) -@SwipeControlsCompatibility @Version("0.0.1") class SwipeControlsResourcePatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( PreferenceScreen( - "revanced_swipe_controls", StringResource("revanced_swipe_controls_title", "Swipe controls"), listOf( + "revanced_swipe_controls_preference_screen", + StringResource("revanced_swipe_controls_preference_screen_title", "Swipe controls"), + listOf( SwitchPreference( - "revanced_enable_swipe_brightness", - StringResource("revanced_swipe_brightness_enabled_title", "Enable brightness gesture"), - true, + "revanced_swipe_brightness", + StringResource("revanced_swipe_brightness_title", "Enable brightness gesture"), StringResource("revanced_swipe_brightness_summary_on", "Brightness swipe is enabled"), StringResource("revanced_swipe_brightness_summary_off", "Brightness swipe is disabled") ), SwitchPreference( - "revanced_enable_swipe_volume", - StringResource("revanced_swipe_volume_enabled_title", "Enable volume gesture"), - true, + "revanced_swipe_volume", + StringResource("revanced_swipe_volume_title", "Enable volume gesture"), StringResource("revanced_swipe_volume_summary_on", "Volume swipe is enabled"), StringResource("revanced_swipe_volume_summary_off", "Volume swipe is disabled") ), SwitchPreference( - "revanced_enable_press_to_swipe", - StringResource("revanced_press_to_swipe_enabled_title", "Enable press-to-swipe gesture"), - false, - StringResource("revanced_press_to_swipe_summary_on", "Press-to-swipe is enabled"), - StringResource("revanced_press_to_swipe_summary_off", "Press-to-swipe is disabled") + "revanced_swipe_press_to_engage", + StringResource("revanced_swipe_press_to_engage_title", "Enable press-to-swipe gesture"), + StringResource("revanced_swipe_press_to_engage_summary_on", "Press-to-swipe is enabled"), + StringResource("revanced_swipe_press_to_engage_summary_off", "Press-to-swipe is disabled") ), SwitchPreference( - "revanced_enable_swipe_haptic_feedback", - StringResource("revanced_swipe_haptic_feedback_enabled_title", "Enable haptic feedback"), - true, + "revanced_swipe_haptic_feedback", + StringResource("revanced_swipe_haptic_feedback_title", "Enable haptic feedback"), StringResource("revanced_swipe_haptic_feedback_summary_on", "Haptic feedback is enabled"), StringResource("revanced_swipe_haptic_feedback_summary_off", "Haptic feedback is disabled") ), TextPreference( "revanced_swipe_overlay_timeout", StringResource("revanced_swipe_overlay_timeout_title", "Swipe overlay timeout"), - InputType.NUMBER, - "500", StringResource( "revanced_swipe_overlay_timeout_summary", "The amount of milliseconds the overlay is visible" - ) + ), + InputType.NUMBER ), TextPreference( - "revanced_swipe_overlay_text_size", - StringResource("revanced_swipe_overlay_text_size_title", "Swipe overlay text size"), - InputType.NUMBER, - "22", - StringResource("revanced_swipe_overlay_text_size_summary", "The text size for swipe overlay") + "revanced_swipe_text_overlay_size", + StringResource("revanced_swipe_text_overlay_size_title", "Swipe overlay text size"), + StringResource("revanced_swipe_text_overlay_size_summary", "The text size for swipe overlay"), + InputType.NUMBER ), TextPreference( "revanced_swipe_overlay_background_alpha", StringResource("revanced_swipe_overlay_background_alpha_title", "Swipe background visibility"), - InputType.NUMBER, - "127", StringResource( "revanced_swipe_overlay_background_alpha_summary", "The visibility of swipe overlay background" - ) + ), + InputType.NUMBER ), TextPreference( - "revanced_swipe_magnitude_threshold", - StringResource("revanced_swipe_magnitude_threshold_title", "Swipe magnitude threshold"), - InputType.NUMBER, - "30", + "revanced_swipe_threshold", + StringResource("revanced_swipe_threshold_title", "Swipe magnitude threshold"), StringResource( - "revanced_swipe_magnitude_threshold_summary", + "revanced_swipe_threshold_summary", "The amount of threshold for swipe to occur" - ) + ), + InputType.NUMBER ) ), - StringResource("revanced_swipe_controls_summary","Control volume and brightness") + StringResource("revanced_swipe_controls_preference_screen_summary","Control volume and brightness") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt index 383eb476a..c03a3e7f9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.autocaptions.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class AutoCaptionsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt index 25e3e8521..675a7369b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt @@ -33,11 +33,10 @@ class AutoCaptionsPatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( SwitchPreference( - "revanced_autocaptions_enabled", - StringResource("revanced_autocaptions_enabled_title", "Disable auto captions"), - false, - StringResource("revanced_autocaptions_summary_on", "Auto captions are disabled"), - StringResource("revanced_autocaptions_summary_off", "Auto captions are enabled") + "revanced_auto_captions", + StringResource("revanced_auto_captions_title", "Disable auto captions"), + StringResource("revanced_auto_captions_summary_on", "Auto captions are disabled"), + StringResource("revanced_auto_captions_summary_off", "Auto captions are enabled") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt index 444ffa739..112725358 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/annotations/HideButtonsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.action.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideButtonsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt index cb2c94c04..073d9b05a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/action/patch/HideButtonsPatch.kt @@ -27,34 +27,30 @@ class HideButtonsPatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( - "revanced_hide_buttons", - StringResource("revanced_hide_buttons_title", "Hide action buttons"), + "revanced_hide_buttons_preference_screen", + StringResource("revanced_hide_buttons_preference_screen_title", "Hide action buttons"), listOf( SwitchPreference( "revanced_hide_like_dislike_button", StringResource("revanced_hide_like_dislike_button_title", "Hide like and dislike buttons"), - false, StringResource("revanced_hide_like_dislike_button_summary_on", "Like and dislike buttons are hidden"), StringResource("revanced_hide_like_dislike_button_summary_off", "Like and dislike buttons are shown") ), SwitchPreference( "revanced_hide_download_button", StringResource("revanced_hide_download_button_title", "Hide download button"), - false, StringResource("revanced_hide_download_button_summary_on", "Download button is hidden"), StringResource("revanced_hide_download_button_summary_off", "Download button is shown") ), SwitchPreference( "revanced_hide_playlist_button", StringResource("revanced_hide_playlist_button_title", "Hide playlist button"), - false, StringResource("revanced_hide_playlist_button_summary_on", "Playlist button is hidden"), StringResource("revanced_hide_playlist_button_summary_off", "Playlist button is shown") ), SwitchPreference( "revanced_hide_clip_button", StringResource("revanced_hide_clip_button_title", "Hide clip button"), - false, StringResource("revanced_hide_clip_button_summary_on", "Clip button is hidden"), StringResource("revanced_hide_clip_button_summary_off", "Clip button is shown"), StringResource("revanced_hide_clip_button_user_dialog_message", @@ -63,12 +59,11 @@ class HideButtonsPatch : ResourcePatch { SwitchPreference( "revanced_hide_action_buttons", StringResource("revanced_hide_action_buttons_title", "Hide all other action buttons"), - false, StringResource("revanced_hide_action_buttons_summary_on", "Share, remix, thanks, shop, live chat buttons are hidden"), StringResource("revanced_hide_action_buttons_summary_off", "Share, remix, thanks, shop, live chat buttons are shown") ) ), - StringResource("revanced_hide_buttons_summary", "Hide or show buttons under videos") + StringResource("revanced_hide_buttons_preference_screen_summary", "Hide or show buttons under videos") ) ) return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt index 78a4de883..278fb0c2f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/annotations/AutoplayButtonCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.autoplay.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class AutoplayButtonCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/fingerprints/LayoutConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/fingerprints/LayoutConstructorFingerprint.kt index cc9c20ccc..92d33ce31 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/fingerprints/LayoutConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/fingerprints/LayoutConstructorFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object LayoutConstructorFingerprint : MethodFingerprint( strings = listOf("1.0x"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("YouTubeControlsOverlay;") } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt index 2700bbad9..ff10f48f9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/autoplay/patch/HideAutoplayButtonPatch.kt @@ -40,7 +40,6 @@ class HideAutoplayButtonPatch : BytecodePatch( SwitchPreference( "revanced_hide_autoplay_button", StringResource("revanced_hide_autoplay_button_title", "Hide autoplay button"), - true, StringResource("revanced_hide_autoplay_button_summary_on", "Autoplay button is hidden"), StringResource("revanced_hide_autoplay_button_summary_off", "Autoplay button is shown") ), @@ -69,7 +68,7 @@ class HideAutoplayButtonPatch : BytecodePatch( val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction // can be clobbered because this register is overwritten after the injected code - val clobberRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA + val clobberRegister = instruction<OneRegisterInstruction>(insertIndex).registerA addInstructions( insertIndex, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt index c31480999..849d2e18e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/annotations/HideCaptionsButtonCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.captions.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideCaptionsButtonCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/patch/HideCaptionsButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/patch/HideCaptionsButtonPatch.kt index fcd7773be..a8aa8dbd3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/patch/HideCaptionsButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/captions/patch/HideCaptionsButtonPatch.kt @@ -32,7 +32,6 @@ class HideCaptionsButtonPatch : BytecodePatch(listOf( SwitchPreference( "revanced_hide_captions_button", StringResource("revanced_hide_captions_button_title", "Hide captions button"), - false, StringResource("revanced_hide_captions_button_summary_on", "Captions button is hidden"), StringResource("revanced_hide_captions_button_summary_off", "Captions button is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/patch/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/patch/HideCastButtonPatch.kt index 884e3adbc..03f57266a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/patch/HideCastButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/cast/patch/HideCastButtonPatch.kt @@ -29,7 +29,6 @@ class HideCastButtonPatch : BytecodePatch() { SwitchPreference( "revanced_hide_cast_button", StringResource("revanced_hide_cast_button_title", "Hide cast button"), - true, StringResource("revanced_hide_cast_button_summary_on", "Cast button is hidden"), StringResource("revanced_hide_cast_button_summary_off", "Cast button is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt index 234851058..e298888c1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/annotations/NavigationButtonsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.navigation.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class NavigationButtonsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/InitializeButtonsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/InitializeButtonsFingerprint.kt index e7c62c85d..33d384042 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/InitializeButtonsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/InitializeButtonsFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.WideLiteralInstruction object InitializeButtonsFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { it.opcode == Opcode.CONST && (it as WideLiteralInstruction).wideLiteral == ResolvePivotBarFingerprintsPatch.imageOnlyTabResourceId diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarConstructorFingerprint.kt index 98991910f..4500faf65 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/fingerprints/PivotBarConstructorFingerprint.kt @@ -5,6 +5,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags object PivotBarConstructorFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, strings = listOf("com.google.android.apps.youtube.app.endpoint.flags") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/patch/NavigationButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/patch/NavigationButtonsPatch.kt index 4a2f584ab..477fdf269 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/patch/NavigationButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/patch/NavigationButtonsPatch.kt @@ -41,27 +41,24 @@ class NavigationButtonsPatch : BytecodePatch(listOf(AddCreateButtonViewFingerpri override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( - "revanced_navigation_buttons", - StringResource("revanced_navigation_buttons", "Navigation button settings"), + "revanced_navigation_buttons_preference_screen", + StringResource("revanced_navigation_buttons_preference_screen_title", "Navigation button settings"), listOf( SwitchPreference( "revanced_hide_home_button", StringResource("revanced_hide_home_button_title", "Hide home button"), - false, StringResource("revanced_hide_home_button_summary_on", "Home button is hidden"), StringResource("revanced_hide_home_button_summary_off", "Home button is shown") ), SwitchPreference( "revanced_hide_shorts_button", StringResource("revanced_hide_shorts_button_title", "Hide shorts button"), - true, StringResource("revanced_hide_shorts_button_summary_on", "Shorts button is hidden"), StringResource("revanced_hide_shorts_button_summary_off", "Shorts button is shown") ), SwitchPreference( "revanced_hide_subscriptions_button", StringResource("revanced_hide_subscriptions_button_title", "Hide subscriptions button"), - false, StringResource( "revanced_hide_subscriptions_button_summary_on", "Home subscriptions is hidden" @@ -71,7 +68,6 @@ class NavigationButtonsPatch : BytecodePatch(listOf(AddCreateButtonViewFingerpri SwitchPreference( "revanced_hide_create_button", StringResource("revanced_hide_create_button_title", "Hide create button"), - true, StringResource("revanced_hide_create_button_summary_on", "Create button is hidden"), StringResource("revanced_hide_create_button_summary_off", "Create button is shown") ), @@ -81,7 +77,6 @@ class NavigationButtonsPatch : BytecodePatch(listOf(AddCreateButtonViewFingerpri "revanced_switch_create_with_notifications_button_title", "Switch create with notifications button" ), - true, StringResource( "revanced_switch_create_with_notifications_button_summary_on", "Create button is switched with notifications" @@ -149,7 +144,7 @@ class NavigationButtonsPatch : BytecodePatch(listOf(AddCreateButtonViewFingerpri }!!.index val conditionalCheckIndex = stringIndex - 1 - val conditionRegister = (instruction(conditionalCheckIndex) as OneRegisterInstruction).registerA + val conditionRegister = instruction<OneRegisterInstruction>(conditionalCheckIndex).registerA addInstructions( conditionalCheckIndex, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/utils/InjectionUtils.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/utils/InjectionUtils.kt index ae60c1aa7..98036c67e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/utils/InjectionUtils.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/navigation/utils/InjectionUtils.kt @@ -20,7 +20,7 @@ internal object InjectionUtils { // Register to pass to the hook val registerIndex = insertIndex - 1 // MOVE_RESULT_OBJECT is always the previous instruction - val register = (injectTarget.instruction(registerIndex) as OneRegisterInstruction).registerA + val register = injectTarget.instruction<OneRegisterInstruction>(registerIndex).registerA injectTarget.addInstruction( insertIndex, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt index ecae5d525..a939d9b7e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/annotations/PlayerButtonBackgroundCompatibility.kt @@ -2,22 +2,6 @@ package app.revanced.patches.youtube.layout.buttons.player.background.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class PlayerButtonBackgroundCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/patch/PlayerButtonBackgroundPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/patch/PlayerButtonBackgroundPatch.kt index b9951abd4..ead1c8658 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/patch/PlayerButtonBackgroundPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/background/patch/PlayerButtonBackgroundPatch.kt @@ -12,16 +12,12 @@ import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.youtube.layout.buttons.player.background.annotations.PlayerButtonBackgroundCompatibility import org.w3c.dom.Element -@Patch +@Patch(false) @Name("remove-player-button-background") @Description("Removes the background from the video player buttons.") @PlayerButtonBackgroundCompatibility @Version("0.0.1") class PlayerButtonBackgroundPatch : ResourcePatch { - private companion object { - const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml" - } - override fun execute(context: ResourceContext): PatchResult { context.xmlEditor[RESOURCE_FILE_PATH].use { editor -> editor.file.doRecursively node@{ node -> @@ -35,4 +31,8 @@ class PlayerButtonBackgroundPatch : ResourcePatch { return PatchResultSuccess() } + + private companion object { + const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml" + } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt index d2137b01c..1f20ff2fb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/annotations/HidePlayerButtonsCompatibility.kt @@ -3,10 +3,6 @@ package app.revanced.patches.youtube.layout.buttons.player.hide.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf() - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HidePlayerButtonsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/patch/HidePlayerButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/patch/HidePlayerButtonsPatch.kt index 1ea9cfbad..3b22d811c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/patch/HidePlayerButtonsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/player/hide/patch/HidePlayerButtonsPatch.kt @@ -41,7 +41,6 @@ class HidePlayerButtonsPatch : BytecodePatch( "revanced_hide_player_buttons_title", "Hide previous & next video buttons" ), - false, StringResource( "revanced_hide_player_buttons_summary_on", "Buttons are hidden" @@ -55,7 +54,7 @@ class HidePlayerButtonsPatch : BytecodePatch( PlayerControlsVisibilityModelFingerprint.result?.apply { val callIndex = scanResult.patternScanResult!!.endIndex - val callInstruction = mutableMethod.instruction(callIndex) as Instruction3rc + val callInstruction = mutableMethod.instruction<Instruction3rc>(callIndex) // overriding this parameter register hides the previous and next buttons val hasNextParameterRegister = callInstruction.startRegister + ParameterOffsets.HAS_NEXT diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt index 8ea55f844..1523ca1c2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/annotations/AlbumCardsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.albumcards.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class AlbumCardsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt index 79874b37a..9382220c2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt @@ -14,7 +14,7 @@ object AlbumCardsFingerprint : MethodFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == AlbumCardsResourcePatch.albumCardId diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/patch/AlbumCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/patch/AlbumCardsPatch.kt index f9ae2950e..bebceae5f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/patch/AlbumCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/bytecode/patch/AlbumCardsPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.hide.albumcards.bytecode.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -29,16 +30,22 @@ class AlbumCardsPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext): PatchResult { - val albumCardsResult = AlbumCardsFingerprint.result!! - val albumCardsMethod = albumCardsResult.mutableMethod + AlbumCardsFingerprint.result?.let { + it.mutableMethod.apply { + val checkCastAnchorIndex = it.scanResult.patternScanResult!!.endIndex + val insertIndex = checkCastAnchorIndex + 1 - val checkCastAnchorIndex = albumCardsResult.scanResult.patternScanResult!!.endIndex + val albumCardViewRegister = instruction<OneRegisterInstruction>(checkCastAnchorIndex).registerA - albumCardsMethod.addInstruction( - checkCastAnchorIndex + 1, """ - invoke-static {v${(albumCardsMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideAlbumCardsPatch;->hideAlbumCards(Landroid/view/View;)V - """ - ) + addInstruction( + insertIndex, + "invoke-static {v$albumCardViewRegister}, " + + "Lapp/revanced/integrations/patches/HideAlbumCardsPatch;" + + "->" + + "hideAlbumCards(Landroid/view/View;)V" + ) + } + } ?: return AlbumCardsFingerprint.toErrorResult() return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/resource/patch/AlbumCardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/resource/patch/AlbumCardsResourcePatch.kt index 50621ee06..8193f3f7f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/resource/patch/AlbumCardsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/albumcards/resource/patch/AlbumCardsResourcePatch.kt @@ -27,7 +27,6 @@ class AlbumCardsResourcePatch : ResourcePatch { SwitchPreference( "revanced_hide_album_cards", StringResource("revanced_hide_album_cards_title", "Hide album cards"), - false, StringResource("revanced_hide_album_cards_summary_on", "Album cards are hidden"), StringResource("revanced_hide_album_cards_summary_off", "Album cards are shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt index ad3edf3cc..b3245b815 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/annotations/HideArtistCardCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.artistcards.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideArtistCardCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/patch/HideArtistCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/patch/HideArtistCardsPatch.kt index c6153f34e..e4921df9e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/patch/HideArtistCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/artistcards/patch/HideArtistCardsPatch.kt @@ -28,7 +28,6 @@ class HideArtistCardsPatch : ResourcePatch { SwitchPreference( "revanced_hide_artist_cards", StringResource("revanced_hide_artist_cards_title", "Hide artist cards"), - false, StringResource("revanced_hide_artist_cards_on", "Artist cards is hidden"), StringResource("revanced_hide_artist_cards_off", "Artist cards is shown") ), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt index 95fd3e7e8..af446cfe8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/annotations/BreakingNewsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.breakingnews.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class BreakingNewsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/fingerprints/BreakingNewsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/fingerprints/BreakingNewsFingerprint.kt index b4c3d8363..eb54fbdb6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/fingerprints/BreakingNewsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/fingerprints/BreakingNewsFingerprint.kt @@ -14,7 +14,7 @@ object BreakingNewsFingerprint : MethodFingerprint( Opcode.CHECK_CAST, Opcode.IPUT_OBJECT, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == BreakingNewsResourcePatch.horizontalCardListId diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/patch/BreakingNewsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/patch/BreakingNewsPatch.kt index 0b5cf1182..d11423ed3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/patch/BreakingNewsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/bytecode/patch/BreakingNewsPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.hide.breakingnews.bytecode.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -24,22 +25,29 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @BreakingNewsCompatibility @Version("0.0.1") class BreakingNewsPatch : BytecodePatch( - listOf( - BreakingNewsFingerprint, - ) + listOf(BreakingNewsFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - val breakingNewsResult = BreakingNewsFingerprint.result!! - val breakingNewsMethod = breakingNewsResult.mutableMethod + BreakingNewsFingerprint.result?.let { + val insertIndex = it.scanResult.patternScanResult!!.endIndex - 1 + val moveResultIndex = insertIndex - 1 - val moveResultObjectIndex = - breakingNewsResult.scanResult.patternScanResult!!.endIndex - 2 + it.mutableMethod.apply { + val breakingNewsViewRegister = instruction<OneRegisterInstruction>(moveResultIndex).registerA + + addInstruction( + insertIndex, + """ + invoke-static {v$breakingNewsViewRegister}, + Lapp/revanced/integrations/patches/HideBreakingNewsPatch; + -> + hideBreakingNews(Landroid/view/View;)V + """ + ) + } + + } ?: return BreakingNewsFingerprint.toErrorResult() - breakingNewsMethod.addInstruction( - moveResultObjectIndex + 1, """ - invoke-static {v${(breakingNewsMethod.instruction(moveResultObjectIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideBreakingNewsPatch;->hideBreakingNews(Landroid/view/View;)V - """ - ) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/resource/patch/BreakingNewsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/resource/patch/BreakingNewsResourcePatch.kt index ffb32092e..f310ac764 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/resource/patch/BreakingNewsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/breakingnews/resource/patch/BreakingNewsResourcePatch.kt @@ -25,7 +25,6 @@ class BreakingNewsResourcePatch : ResourcePatch { SwitchPreference( "revanced_hide_breaking_news", StringResource("revanced_hide_breaking_news_title", "Hide breaking news"), - true, StringResource("revanced_hide_breaking_news_summary_on", "Breaking news are hidden"), StringResource("revanced_hide_breaking_news_summary_off", "Breaking news are shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt deleted file mode 100644 index c852dc42b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/CommentsCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.comments.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class CommentsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt new file mode 100644 index 000000000..27f8151f0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/annotations/HideCommentsCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.comments.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideCommentsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/bytecode/fingerprints/ShortsCommentsButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/bytecode/fingerprints/ShortsCommentsButtonFingerprint.kt deleted file mode 100644 index 1bfb297f3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/bytecode/fingerprints/ShortsCommentsButtonFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.comments.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hide.comments.resource.patch.CommentsResourcePatch -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object ShortsCommentsButtonFingerprint : MethodFingerprint( - "V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("Z", "Z", "L"), - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { - it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == CommentsResourcePatch.shortsCommentsButtonId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/bytecode/patch/CommentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/bytecode/patch/CommentsPatch.kt deleted file mode 100644 index 7e6708278..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/bytecode/patch/CommentsPatch.kt +++ /dev/null @@ -1,62 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.comments.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.hide.comments.annotations.CommentsCompatibility -import app.revanced.patches.youtube.layout.hide.comments.bytecode.fingerprints.ShortsCommentsButtonFingerprint -import app.revanced.patches.youtube.layout.hide.comments.resource.patch.CommentsResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class, CommentsResourcePatch::class]) -@Name("comments") -@Description("Hides components related to comments.") -@CommentsCompatibility -@Version("0.0.1") -class CommentsPatch : BytecodePatch( - listOf( - ShortsCommentsButtonFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val shortsCommentsButtonResult = ShortsCommentsButtonFingerprint.result!! - val shortsCommentsButtonMethod = shortsCommentsButtonResult.mutableMethod - - val checkCastAnchorFingerprint = object : MethodFingerprint( - opcodes = listOf( - Opcode.CONST, - Opcode.CONST_HIGH16, - Opcode.IF_EQZ, - Opcode.CONST, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - ) - ) {} - - val checkCastAnchorIndex = checkCastAnchorFingerprint.also { - it.resolve(context, shortsCommentsButtonMethod, shortsCommentsButtonResult.classDef) - }.result!!.scanResult.patternScanResult!!.endIndex - - shortsCommentsButtonMethod.addInstructions( - checkCastAnchorIndex + 1, """ - invoke-static {v${(shortsCommentsButtonMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideShortsCommentsButtonPatch;->hideShortsCommentsButton(Landroid/view/View;)V - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/resource/patch/CommentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/patch/CommentsPatch.kt similarity index 61% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/resource/patch/CommentsResourcePatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/patch/CommentsPatch.kt index c16d6f82e..5ebb44d14 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/resource/patch/CommentsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/comments/patch/CommentsPatch.kt @@ -1,5 +1,6 @@ -package app.revanced.patches.youtube.layout.hide.comments.resource.patch +package app.revanced.patches.youtube.layout.hide.comments.patch +import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.ResourceContext @@ -7,58 +8,44 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.layout.hide.comments.annotations.CommentsCompatibility +import app.revanced.patches.youtube.layout.hide.comments.annotations.HideCommentsCompatibility import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -@Name("comments-resource-patch") -@CommentsCompatibility +@Patch +@Name("comments") +@Description("Hides components related to comments.") +@HideCommentsCompatibility @DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) @Version("0.0.1") -class CommentsResourcePatch : ResourcePatch { - companion object { - internal var shortsCommentsButtonId: Long = -1 - } - +class CommentsPatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( PreferenceScreen( - "revanced_comments", - StringResource("revanced_comments_title", "Comments"), + "revanced_comments_preference_screen", + StringResource("revanced_comments_preference_screen_title", "Comments"), listOf( SwitchPreference( "revanced_hide_comments_section", StringResource("revanced_hide_comments_section_title", "Hide comments section"), - false, StringResource("revanced_hide_comments_section_summary_on", "Comment section is hidden"), StringResource("revanced_hide_comments_section_summary_off", "Comment section is shown") ), SwitchPreference( "revanced_hide_preview_comment", StringResource("revanced_hide_preview_comment_title", "Hide preview comment"), - false, StringResource("revanced_hide_preview_comment_on", "Preview comment is hidden"), StringResource("revanced_hide_preview_comment_off", "Preview comment is shown") - ), - SwitchPreference( - "revanced_hide_shorts_comments_button", - StringResource("revanced_hide_shorts_comments_button_title", "Hide shorts comments button"), - false, - StringResource("revanced_hide_shorts_comments_button_on", "Shorts comments button is hidden"), - StringResource("revanced_hide_shorts_comments_button_off", "Shorts comments button is shown") - ), + ) ), - StringResource("revanced_comments_summary", "Manage the visibility of comments section components") + StringResource("revanced_comments_preference_screen_summary", "Manage the visibility of comments section components") ) ) - shortsCommentsButtonId = ResourceMappingPatch.resourceMappings.single { - it.type == "drawable" && it.name == "ic_right_comment_32c" - }.id - return PatchResultSuccess() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt index 70629074e..f6776877b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.crowdfundingbox.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class CrowdfundingBoxCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt index 0ad96367d..1ed367227 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt @@ -11,7 +11,7 @@ object CrowdfundingBoxFingerprint : MethodFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.IPUT_OBJECT, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == CrowdfundingBoxResourcePatch.crowdfundingBoxId diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt index 94d3b103f..c6373f635 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt @@ -33,7 +33,7 @@ class CrowdfundingBoxPatch : BytecodePatch( CrowdfundingBoxFingerprint.result?.let { it.mutableMethod.apply { val insertIndex = it.scanResult.patternScanResult!!.endIndex - val objectRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA + val objectRegister = instruction<TwoRegisterInstruction>(insertIndex).registerA addInstruction(insertIndex, "invoke-static {v$objectRegister}, $INTEGRATIONS_METHOD_DESCRIPTOR") } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt index dc639f438..feb830194 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/crowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt @@ -27,7 +27,6 @@ class CrowdfundingBoxResourcePatch : ResourcePatch { SwitchPreference( "revanced_hide_crowdfunding_box", StringResource("revanced_hide_crowdfunding_box_title", "Hide crowdfunding box"), - false, StringResource("revanced_hide_crowdfunding_box_summary_on", "Crowdfunding box is hidden"), StringResource("revanced_hide_crowdfunding_box_summary_off", "Crowdfunding box is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt index c0c561520..47d278010 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/annotations/HideEndscreenCardsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.endscreencards.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideEndscreenCardsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt index 0931de5f1..55521394a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt @@ -13,7 +13,7 @@ object LayoutCircleFingerprint : MethodFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == HideEndscreenCardsResourcePatch.layoutCircle diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt index 9fcd0dc43..603bebdd3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt @@ -13,7 +13,7 @@ object LayoutIconFingerprint : MethodFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == HideEndscreenCardsResourcePatch.layoutIcon diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt index bec34caf5..01307ad6c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt @@ -13,7 +13,7 @@ object LayoutVideoFingerprint : MethodFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == HideEndscreenCardsResourcePatch.layoutVideo diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/patch/HideEndscreenCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/patch/HideEndscreenCardsPatch.kt index 69adc82c6..624e3c4eb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/patch/HideEndscreenCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/bytecode/patch/HideEndscreenCardsPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.hide.endscreencards.bytecode.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -35,19 +36,23 @@ class HideEndscreenCardsPatch : BytecodePatch( ) { override fun execute(context: BytecodeContext): PatchResult { fun MethodFingerprint.injectHideCall() { - val layoutResult = result!! - val layoutMethod = layoutResult.mutableMethod + val layoutResult = result ?: throw toErrorResult() + layoutResult.mutableMethod.apply { + val insertIndex = layoutResult.scanResult.patternScanResult!!.endIndex + 1 + val viewRegister = instruction<Instruction21c>(insertIndex - 1).registerA - val checkCastIndex = layoutResult.scanResult.patternScanResult!!.endIndex - val viewRegister = (layoutMethod.instruction(checkCastIndex) as Instruction21c).registerA - - layoutMethod.addInstruction( - checkCastIndex + 1, - "invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V" - ) + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V" + ) + } } - - listOf(LayoutCircleFingerprint, LayoutIconFingerprint, LayoutVideoFingerprint).forEach(MethodFingerprint::injectHideCall) + + listOf( + LayoutCircleFingerprint, + LayoutIconFingerprint, + LayoutVideoFingerprint + ).forEach(MethodFingerprint::injectHideCall) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt index 6dc3d74c5..5919bb5b6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/endscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt @@ -29,7 +29,6 @@ class HideEndscreenCardsResourcePatch : ResourcePatch { SwitchPreference( "revanced_hide_endscreen_cards", StringResource("revanced_hide_endscreen_cards_title", "Hide end screen cards"), - true, StringResource("revanced_hide_endscreen_cards_summary_on", "End screen cards are hidden"), StringResource("revanced_hide_endscreen_cards_summary_off", "End screen cards are shown") ), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt new file mode 100644 index 000000000..e45cafd7b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/annotations/HideFilterBar.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideFilterBar \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/FilterBarHeightFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/FilterBarHeightFingerprint.kt new file mode 100644 index 000000000..6178c4c89 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/FilterBarHeightFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.filterBarHeightId +import org.jf.dexlib2.Opcode + +object FilterBarHeightFingerprint : LiteralOpcodesFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IPUT + ), + filterBarHeightId +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/LiteralOpcodesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/LiteralOpcodesFingerprint.kt new file mode 100644 index 000000000..3189e17ec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/LiteralOpcodesFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + + +abstract class LiteralOpcodesFingerprint(opcodes: List<Opcode>, literal: Long) : MethodFingerprint( + opcodes = opcodes, + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { instruction -> + if (instruction.opcode != Opcode.CONST) return@any false + + val wideLiteral = (instruction as WideLiteralInstruction).wideLiteral + + literal == wideLiteral + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/RelatedChipCloudFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/RelatedChipCloudFingerprint.kt new file mode 100644 index 000000000..be0ef5cee --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/RelatedChipCloudFingerprint.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.relatedChipCloudMarginId +import org.jf.dexlib2.Opcode + +object RelatedChipCloudFingerprint : LiteralOpcodesFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT + ), + relatedChipCloudMarginId +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/SearchResultsChipBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/SearchResultsChipBarFingerprint.kt new file mode 100644 index 000000000..82deee685 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/fingerprints/SearchResultsChipBarFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.fingerprints + +import app.revanced.patches.youtube.layout.hide.filterbar.patch.HideFilterBarResourcePatch.Companion.barContainerHeightId +import org.jf.dexlib2.Opcode + +object SearchResultsChipBarFingerprint : LiteralOpcodesFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT + ), + barContainerHeightId +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarPatch.kt new file mode 100644 index 000000000..ea69ddbe3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarPatch.kt @@ -0,0 +1,87 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.layout.hide.filterbar.annotations.HideFilterBar +import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.FilterBarHeightFingerprint +import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.RelatedChipCloudFingerprint +import app.revanced.patches.youtube.layout.hide.filterbar.fingerprints.SearchResultsChipBarFingerprint +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction + +@Patch +@Name("hide-filter-bar") +@Description("Hides the filter bar in video feeds.") +@DependsOn([HideFilterBarResourcePatch::class]) +@HideFilterBar +@Version("0.0.1") +class HideFilterBarPatch : BytecodePatch( + listOf( + RelatedChipCloudFingerprint, + SearchResultsChipBarFingerprint, + FilterBarHeightFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + FilterBarHeightFingerprint.patch<TwoRegisterInstruction> { register -> + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->hideInFeed(I)I + move-result v$register + """ + } + + RelatedChipCloudFingerprint.patch<OneRegisterInstruction>(1) { register -> + "invoke-static { v$register }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideInRelatedVideos(Landroid/view/View;)V" + } + + SearchResultsChipBarFingerprint.patch<OneRegisterInstruction>(-1, -2) { register -> + """ + invoke-static { v$register }, $INTEGRATIONS_CLASS_DESCRIPTOR->hideInSearch(I)I + move-result v$register + """ + } + + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/patches/HideFilterBarPatch;" + + /** + * Patch a [MethodFingerprint] with a given [instructions]. + * + * @param RegisterInstruction The type of instruction to get the register from. + * @param insertIndexOffset The offset to add to the end index of the [MethodFingerprint]. + * @param hookRegisterOffset The offset to add to the register of the hook. + * @param instructions The instructions to add with the register as a parameter. + */ + private fun <RegisterInstruction: OneRegisterInstruction> MethodFingerprint.patch( + insertIndexOffset: Int = 0, + hookRegisterOffset: Int = 0, + instructions: (Int) -> String + ) = + result?.let { + it.mutableMethod.apply { + val endIndex = it.scanResult.patternScanResult!!.endIndex + + val insertIndex = endIndex + insertIndexOffset + val register = instruction<RegisterInstruction>(endIndex + hookRegisterOffset).registerA + + addInstructions(insertIndex, instructions(register)) + } + } ?: throw toErrorResult() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarResourcePatch.kt new file mode 100644 index 000000000..45bddf581 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/filterbar/patch/HideFilterBarResourcePatch.kt @@ -0,0 +1,95 @@ +package app.revanced.patches.youtube.layout.hide.filterbar.patch + +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch + +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +@Version("0.0.1") +class HideFilterBarResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + PreferenceScreen( + "revanced_hide_filter_bar_preference", + StringResource( + "revanced_hide_filter_bar_preference_title", + "Hide filter bar" + ), + listOf( + SwitchPreference( + "revanced_hide_filter_bar_feed_in_feed", + StringResource( + "revanced_hide_filter_bar_feed_in_feed_title", + "Hide in feed" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_feed_summary_on", + "Hidden in feed" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_feed_summary_off", + "Shown in feed" + ) + ), + SwitchPreference( + "revanced_hide_filter_bar_feed_in_search", + StringResource( + "revanced_hide_filter_bar_feed_in_search_title", + "Hide in search" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_search_summary_on", + "Hidden in search" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_search_summary_off", + "Shown in search" + ) + ), + SwitchPreference( + "revanced_hide_filter_bar_feed_in_related_videos", + StringResource( + "revanced_hide_filter_bar_feed_in_related_videos_title", + "Hide in related videos" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_related_videos_summary_on", + "Hidden in related videos" + ), + StringResource( + "revanced_hide_filter_bar_feed_in_related_videos_summary_off", + "Shown in related videos" + ) + ), + ), + StringResource( + "revanced_hide_filter_bar_preference_summary", + "Manage the visibility of the filter bar in the feed, search and related videos" + ) + ) + ) + + relatedChipCloudMarginId = "related_chip_cloud_reduced_margins".layoutResourceId("layout") + filterBarHeightId = "filter_bar_height".layoutResourceId() + barContainerHeightId = "bar_container_height".layoutResourceId() + + return PatchResultSuccess() + } + + internal companion object { + var filterBarHeightId = -1L + var relatedChipCloudMarginId = -1L + var barContainerHeightId = -1L + + private fun String.layoutResourceId(type: String = "dimen") = + ResourceMappingPatch.resourceMappings.single { it.type == type && it.name == this }.id + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt index ae7f3beeb..8ab0a1e5c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/annotations/HideFloatingMicrophoneButtonCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.floatingmicrophone.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideFloatingMicrophoneButtonCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/fingerprints/ShowFloatingMicrophoneButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/fingerprints/ShowFloatingMicrophoneButtonFingerprint.kt index ed72bd968..276cfbe4b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/fingerprints/ShowFloatingMicrophoneButtonFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/fingerprints/ShowFloatingMicrophoneButtonFingerprint.kt @@ -11,7 +11,7 @@ object ShowFloatingMicrophoneButtonFingerprint : MethodFingerprint( Opcode.IF_EQZ, Opcode.RETURN_VOID ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { (it as? WideLiteralInstruction)?.wideLiteral == HideFloatingMicrophoneButtonResourcePatch.fabButtonId } == true diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonPatch.kt index 30f02c143..1d50b18db 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonPatch.kt @@ -29,7 +29,7 @@ class HideFloatingMicrophoneButtonPatch : BytecodePatch( ShowFloatingMicrophoneButtonFingerprint.result?.let { result -> with(result.mutableMethod) { val insertIndex = result.scanResult.patternScanResult!!.startIndex + 1 - val showButtonRegister = (instruction(insertIndex - 1) as TwoRegisterInstruction).registerA + val showButtonRegister = instruction<TwoRegisterInstruction>(insertIndex - 1).registerA addInstructions( insertIndex, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonResourcePatch.kt index 5bc6cc043..ede1d0642 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/floatingmicrophone/patch/HideFloatingMicrophoneButtonResourcePatch.kt @@ -25,7 +25,6 @@ class HideFloatingMicrophoneButtonResourcePatch : ResourcePatch { "revanced_hide_floating_microphone_button_enabled_title", "Hide floating microphone button" ), - true, StringResource("revanced_hide_floating_microphone_button_summary_on", "Microphone button hidden"), StringResource("revanced_hide_floating_microphone_button_summary_off", "Microphone button shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/annotations/HideGetPremiumCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/annotations/HideGetPremiumCompatibility.kt index 917439846..bd210bfc9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/annotations/HideGetPremiumCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/annotations/HideGetPremiumCompatibility.kt @@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.hide.getpremium.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility([Package("com.google.android.youtube", arrayOf("18.15.40", "18.16.37"))]) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideGetPremiumCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/fingerprints/GetPremiumViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/fingerprints/GetPremiumViewFingerprint.kt index 29cca3d03..2cffc2377 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/fingerprints/GetPremiumViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/fingerprints/GetPremiumViewFingerprint.kt @@ -10,7 +10,7 @@ object GetPremiumViewFingerprint : MethodFingerprint( Opcode.INVOKE_VIRTUAL, Opcode.RETURN_VOID ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/google/android/apps/youtube/app/red/presenter/CompactYpcOfferModuleView;" && methodDef.name == "onMeasure" } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/patch/HideGetPremiumVideoAdvertisementPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/patch/HideGetPremiumVideoAdvertisementPatch.kt index 7e3e7b036..1c978a7c8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/patch/HideGetPremiumVideoAdvertisementPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/getpremium/bytecode/patch/HideGetPremiumVideoAdvertisementPatch.kt @@ -36,7 +36,6 @@ class HideGetPremiumPatch : BytecodePatch( SwitchPreference( "revanced_hide_get_premium", StringResource("revanced_hide_get_premium_title", "Hide YouTube Premium advertisement"), - true, StringResource("revanced_hide_get_premium_summary_on", "YouTube Premium advertisement are hidden"), StringResource("revanced_hide_get_premium_summary_off", "YouTube Premium advertisement are shown") ) @@ -45,8 +44,9 @@ class HideGetPremiumPatch : BytecodePatch( GetPremiumViewFingerprint.result?.let { it.mutableMethod.apply { val startIndex = it.scanResult.patternScanResult!!.startIndex - val measuredWidthRegister = (instruction(startIndex) as TwoRegisterInstruction).registerA - val measuredHeightInstruction = instruction(startIndex + 1) as TwoRegisterInstruction + val measuredWidthRegister = instruction<TwoRegisterInstruction>(startIndex).registerA + val measuredHeightInstruction = instruction<TwoRegisterInstruction>(startIndex + 1) + val measuredHeightRegister = measuredHeightInstruction.registerA val tempRegister = measuredHeightInstruction.registerB diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt index d9c458384..8a71676e9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/annotations/HideInfocardsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.infocards.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideInfocardsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/fingerprints/InfocardsMethodCallFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/fingerprints/InfocardsMethodCallFingerprint.kt index 0f258ca1b..08f9ed020 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/fingerprints/InfocardsMethodCallFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/fingerprints/InfocardsMethodCallFingerprint.kt @@ -11,7 +11,7 @@ object InfocardsMethodCallFingerprint : MethodFingerprint( Opcode.IGET_OBJECT, Opcode.INVOKE_INTERFACE, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> (instruction as? WideLiteralInstruction)?.wideLiteral == HideInfocardsResourcePatch.drawerResourceId } == true diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/patch/HideInfoCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/patch/HideInfoCardsPatch.kt index 577a4da0d..d47584343 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/patch/HideInfoCardsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/patch/HideInfoCardsPatch.kt @@ -20,7 +20,8 @@ import app.revanced.patches.youtube.layout.hide.infocards.fingerprints.Infocards import app.revanced.patches.youtube.layout.hide.infocards.resource.patch.HideInfocardsResourcePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.instruction.BuilderInstruction35c +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction @Patch @DependsOn([IntegrationsPatch::class, HideInfocardsResourcePatch::class]) @@ -35,18 +36,17 @@ class HideInfoCardsPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext): PatchResult { - with(InfocardsIncognitoFingerprint.also { + InfocardsIncognitoFingerprint.also { it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef) - }.result!!.mutableMethod) { + }.result!!.mutableMethod.apply { val invokeInstructionIndex = implementation!!.instructions.indexOfFirst { it.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal && - ((it as? BuilderInstruction35c)?.reference.toString() == - "Landroid/view/View;->setVisibility(I)V") + ((it as ReferenceInstruction).reference.toString() == "Landroid/view/View;->setVisibility(I)V") } addInstructions( invokeInstructionIndex, - "invoke-static {v${(instruction(invokeInstructionIndex) as? BuilderInstruction35c)?.registerC}}," + + "invoke-static {v${instruction<FiveRegisterInstruction>(invokeInstructionIndex).registerC}}," + " Lapp/revanced/integrations/patches/HideInfoCardsPatch;->hideInfoCardsIncognito(Landroid/view/View;)V" ) } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/resource/patch/HideInfocardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/resource/patch/HideInfocardsResourcePatch.kt index 47388939a..c5aa4049c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/resource/patch/HideInfocardsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/infocards/resource/patch/HideInfocardsResourcePatch.kt @@ -25,7 +25,6 @@ class HideInfocardsResourcePatch : ResourcePatch { SwitchPreference( "revanced_hide_infocards", StringResource("revanced_hide_infocards_title", "Hide info cards"), - true, StringResource("revanced_hide_infocards_summary_on", "Info cards are hidden"), StringResource("revanced_hide_infocards_summary_off", "Info cards are shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt new file mode 100644 index 000000000..5c580599c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/annotations/HideLoadMoreButtonCompatibility.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.youtube.layout.hide.loadmorebutton.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideLoadMoreButtonCompatibility + diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/bytecode/fingerprints/HideLoadMoreButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/bytecode/fingerprints/HideLoadMoreButtonFingerprint.kt new file mode 100644 index 000000000..2669411e2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/bytecode/fingerprints/HideLoadMoreButtonFingerprint.kt @@ -0,0 +1,29 @@ +package app.revanced.patches.youtube.layout.hide.loadmorebutton.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.hide.loadmorebutton.resource.patch.HideLoadMoreButtonResourcePatch +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object HideLoadMoreButtonFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + parameters = listOf("L", "L", "L", "L"), + opcodes = listOf( + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT + ), + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { + if (it.opcode != Opcode.CONST) return@any false + + val literal = (it as WideLiteralInstruction).wideLiteral + + literal == HideLoadMoreButtonResourcePatch.expandButtonDownId + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/bytecode/patch/HideLoadMoreButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/bytecode/patch/HideLoadMoreButtonPatch.kt new file mode 100644 index 000000000..b63f52302 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/bytecode/patch/HideLoadMoreButtonPatch.kt @@ -0,0 +1,50 @@ +package app.revanced.patches.youtube.layout.hide.loadmorebutton.bytecode.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.layout.hide.loadmorebutton.bytecode.fingerprints.HideLoadMoreButtonFingerprint +import app.revanced.patches.youtube.layout.hide.loadmorebutton.resource.patch.HideLoadMoreButtonResourcePatch +import app.revanced.patches.youtube.layout.hide.loadmorebutton.annotations.HideLoadMoreButtonCompatibility +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction + +@Patch +@Name("hide-load-more-button") +@Description("Hides the button under videos that loads similar videos.") +@DependsOn([HideLoadMoreButtonResourcePatch::class]) +@HideLoadMoreButtonCompatibility +@Version("0.0.1") +class HideLoadMoreButtonPatch : BytecodePatch(listOf(HideLoadMoreButtonFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + HideLoadMoreButtonFingerprint.result?.let { + it.mutableMethod.apply { + val moveRegisterIndex = it.scanResult.patternScanResult!!.endIndex + val viewRegister = instruction<OneRegisterInstruction>(moveRegisterIndex).registerA + + val insertIndex = moveRegisterIndex + 1 + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->hideLoadMoreButton(Landroid/view/View;)V" + ) + } + } ?: return HideLoadMoreButtonFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/patches/HideLoadMoreButtonPatch;" + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/resource/patch/HideLoadMoreButtonResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/resource/patch/HideLoadMoreButtonResourcePatch.kt new file mode 100644 index 000000000..0638a12dd --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/loadmorebutton/resource/patch/HideLoadMoreButtonResourcePatch.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.youtube.layout.hide.loadmorebutton.resource.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.layout.hide.loadmorebutton.annotations.HideLoadMoreButtonCompatibility +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch + +@Name("hide-load-more-button-resource-patch") +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +@HideLoadMoreButtonCompatibility +class HideLoadMoreButtonResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_hide_load_more_button", + StringResource("revanced_hide_load_more_button_title", "Hide Load More button"), + StringResource("revanced_hide_load_more_button_summary_on", "Load More button is hidden"), + StringResource("revanced_hide_load_more_button_summary_off", "Load More button is shown") + ) + ) + + expandButtonDownId = ResourceMappingPatch.resourceMappings.single { + it.type == "layout" && it.name == "expand_button_down" + }.id + + return PatchResultSuccess() + } + + internal companion object { + var expandButtonDownId: Long = -1 + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt index a353abda9..27abf2723 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/annotations/HideEmailAddressCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.personalinformation.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideEmailAddressCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt index 5e5d9fb23..4597c4da4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt @@ -15,7 +15,7 @@ object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint( Opcode.APUT_OBJECT, Opcode.CONST, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == HideEmailAddressResourcePatch.accountSwitcherAccessibilityLabelId diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/patch/HideEmailAddressPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/patch/HideEmailAddressPatch.kt index a6f443d7d..79d0e8542 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/patch/HideEmailAddressPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/bytecode/patch/HideEmailAddressPatch.kt @@ -1,5 +1,6 @@ package app.revanced.patches.youtube.layout.hide.personalinformation.bytecode.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version @@ -29,23 +30,22 @@ class HideEmailAddressPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext): PatchResult { - val accountSwitcherAccessibilityLabelResult = AccountSwitcherAccessibilityLabelFingerprint.result!! - val accountSwitcherAccessibilityLabelMethod = accountSwitcherAccessibilityLabelResult.mutableMethod + AccountSwitcherAccessibilityLabelFingerprint.result?.let { + it.mutableMethod.apply { + val setVisibilityConstIndex = it.scanResult.patternScanResult!!.endIndex - val setVisibilityConstIndex = - accountSwitcherAccessibilityLabelResult.scanResult.patternScanResult!!.endIndex + val setVisibilityConstRegister = + instruction<OneRegisterInstruction>(setVisibilityConstIndex - 2).registerA - val setVisibilityConstRegister = ( - accountSwitcherAccessibilityLabelMethod.instruction - (setVisibilityConstIndex - 2) as OneRegisterInstruction - ).registerA - - accountSwitcherAccessibilityLabelMethod.addInstructions( - setVisibilityConstIndex, """ - invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I - move-result v$setVisibilityConstRegister - """ - ) + addInstructions( + setVisibilityConstIndex, + """ + invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I + move-result v$setVisibilityConstRegister + """ + ) + } + } ?: return AccountSwitcherAccessibilityLabelFingerprint.toErrorResult() return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt index 044c3475f..8d7859393 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt @@ -27,7 +27,6 @@ class HideEmailAddressResourcePatch : ResourcePatch { SwitchPreference( "revanced_hide_email_address", StringResource("revanced_hide_email_address_title", "Hide email in account switcher"), - false, StringResource("revanced_hide_email_address_summary_on", "Email address is hidden"), StringResource("revanced_hide_email_address_summary_off", "Email address is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt new file mode 100644 index 000000000..f235b62ec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/fingerprints/CreatePlayerOverviewFingerprint.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.youtube.layout.hide.player.overlay.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch.HidePlayerOverlayResourcePatch +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object CreatePlayerOverviewFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + opcodes = listOf( + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST + ), + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { + if (it.opcode != Opcode.CONST) return@any false + + val literal = (it as WideLiteralInstruction).wideLiteral + + literal == HidePlayerOverlayResourcePatch.scrimOverlayId + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/patch/HidePlayerOverlayPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/patch/HidePlayerOverlayPatch.kt new file mode 100644 index 000000000..d5b7bd9f4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/bytecode/patch/HidePlayerOverlayPatch.kt @@ -0,0 +1,53 @@ +package app.revanced.patches.youtube.layout.hide.player.overlay.bytecode.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.layout.hide.player.overlay.annotations.HidePlayerOverlayPatchCompatibility +import app.revanced.patches.youtube.layout.hide.player.overlay.bytecode.fingerprints.CreatePlayerOverviewFingerprint +import app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch.HidePlayerOverlayResourcePatch +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +@Patch +@Name("hide-player-overlay") +@Description("Hides the dark background overlay from the player when player controls are visible.") +@DependsOn([HidePlayerOverlayResourcePatch::class]) +@HidePlayerOverlayPatchCompatibility +@Version("0.0.2") +class HidePlayerOverlayPatch : BytecodePatch(listOf(CreatePlayerOverviewFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + CreatePlayerOverviewFingerprint.result?.let { result -> + result.mutableMethod.apply { + val viewRegisterIndex = implementation!!.instructions.indexOfFirst { + val literal = (it as? WideLiteralInstruction)?.wideLiteral + + literal == HidePlayerOverlayResourcePatch.scrimOverlayId + } + 3 + val viewRegister = instruction<OneRegisterInstruction>(viewRegisterIndex).registerA + + val insertIndex = viewRegisterIndex + 1 + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, " + + "$INTEGRATIONS_CLASS_DESCRIPTOR->hidePlayerOverlay(Landroid/widget/ImageView;)V" + ) + } + } ?: return CreatePlayerOverviewFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/HidePlayerOverlayPatch;" + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/patch/HidePlayerOverlayPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/patch/HidePlayerOverlayPatch.kt deleted file mode 100644 index 060073e40..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/patch/HidePlayerOverlayPatch.kt +++ /dev/null @@ -1,46 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.player.overlay.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.hide.player.overlay.annotations.HidePlayerOverlayPatchCompatibility - -@Patch(false) -@Name("hide-player-overlay") -@Description("Hides the dark player overlay when player controls are visible.") -@HidePlayerOverlayPatchCompatibility -@Version("0.0.1") -class HidePlayerOverlayPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - val attributes = arrayOf("height", "width") - - context.xmlEditor[RESOURCE_FILE_PATH].use { editor -> - editor.file.getElementsByTagName("FrameLayout").item(0).childNodes.apply { - for (i in 1 until length) { - val view = item(i) - if ( - view.attributes.getNamedItem("android:id") - ?.nodeValue - ?.endsWith("scrim_overlay") == true - ) { - attributes.forEach { - view.attributes.getNamedItem("android:layout_$it").nodeValue = "0.0dip" - } - break - } - } - } - } - - return PatchResultSuccess() - } - - private companion object { - const val RESOURCE_FILE_PATH = "res/layout/youtube_controls_overlay.xml" - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/resource/patch/HidePlayerOverlayResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/resource/patch/HidePlayerOverlayResourcePatch.kt new file mode 100644 index 000000000..7907f2225 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/player/overlay/resource/patch/HidePlayerOverlayResourcePatch.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.youtube.layout.hide.player.overlay.resource.patch + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.layout.hide.player.overlay.annotations.HidePlayerOverlayPatchCompatibility +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import jdk.jfr.Name + +@Name("hide-player-overlay-resource-patch") +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +@HidePlayerOverlayPatchCompatibility +class HidePlayerOverlayResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + SwitchPreference( + "revanced_hide_player_overlay", + StringResource("revanced_hide_player_overlay_title", "Hide background overlay in player"), + StringResource("revanced_hide_player_overlay_summary_on", "Background overlay is hidden"), + StringResource("revanced_hide_player_overlay_summary_off", "Background overlay is shown") + ) + ) + + scrimOverlayId = ResourceMappingPatch.resourceMappings.single { + it.type == "id" && it.name == "scrim_overlay" + }.id + + return PatchResultSuccess() + } + + internal companion object { + var scrimOverlayId: Long = -1 + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt index aa4639f9e..560e17a8e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/annotations/HideSeekbarCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.seekbar.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideSeekbarCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/patch/HideSeekbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/patch/HideSeekbarPatch.kt index 6fdfa4b84..08102a5c4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/patch/HideSeekbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/seekbar/patch/HideSeekbarPatch.kt @@ -16,11 +16,16 @@ import app.revanced.patches.shared.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference import app.revanced.patches.youtube.layout.hide.seekbar.annotations.HideSeekbarCompatibility +import app.revanced.patches.youtube.layout.seekbar.bytecode.patch.SeekbarColorBytecodePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch @Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) +@DependsOn([ + IntegrationsPatch::class, + SettingsPatch::class, + SeekbarColorBytecodePatch::class // Used to hide the seekbar in the feed and watch history +]) @Name("hide-seekbar") @Description("Hides the seekbar.") @HideSeekbarCompatibility @@ -33,7 +38,6 @@ class HideSeekbarPatch : BytecodePatch( SwitchPreference( "revanced_hide_seekbar", StringResource("revanced_hide_seekbar_title", "Hide seekbar"), - false, StringResource("revanced_hide_seekbar_summary_on", "Seekbar is hidden"), StringResource("revanced_hide_seekbar_summary_off", "Seekbar is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt new file mode 100644 index 000000000..a058e84cd --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/annotations/HideShortsComponentsCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.shorts.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideShortsComponentsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt new file mode 100644 index 000000000..c53e79673 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/BottomNavigationBarFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object BottomNavigationBarFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.MOVE_RESULT_OBJECT, // Refers to bottom navigation bar + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + ), + strings = listOf( + "navigation_endpoint_interaction_logging_extension", + "reel_watch_fragment_watch_while", + ), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt new file mode 100644 index 000000000..2f99a2f0b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/CreateShortsButtonsFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object CreateShortsButtonsFingerprint : MethodFingerprint( + parameters = listOf("Z", "Z", "L"), + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { + if (it.opcode != Opcode.CONST) return@any false + + val literal = (it as WideLiteralInstruction).wideLiteral + + literal == HideShortsComponentsResourcePatch.reelPlayerRightLargeIconSize + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/ReelConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/ReelConstructorFingerprint.kt new file mode 100644 index 000000000..2d6836b2f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/ReelConstructorFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object ReelConstructorFingerprint : MethodFingerprint( + opcodes = listOf(Opcode.INVOKE_VIRTUAL), + customFingerprint = { method, _ -> + method.implementation?.instructions?.any { + if (it.opcode != Opcode.CONST) return@any false + + val literal = (it as WideLiteralInstruction).wideLiteral + + literal == HideShortsComponentsResourcePatch.reelMultipleItemShelfId + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt new file mode 100644 index 000000000..216d7276a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object RenderBottomNavigationBarFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.MONITOR_ENTER, + Opcode.IGET_OBJECT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MONITOR_EXIT, + Opcode.RETURN_VOID, + Opcode.MOVE_EXCEPTION, + Opcode.MONITOR_EXIT, + Opcode.THROW, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt new file mode 100644 index 000000000..70a2ebc0a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/RenderBottomNavigationBarParentFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object RenderBottomNavigationBarParentFingerprint : MethodFingerprint( + parameters = listOf("I", "I", "L", "L", "J", "L"), + strings = listOf("aa") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt new file mode 100644 index 000000000..6c169f2ae --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object SetPivotBarVisibilityFingerprint : MethodFingerprint( + parameters = listOf("Z"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.RETURN_VOID, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt new file mode 100644 index 000000000..170569b9a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/fingerprints/SetPivotBarVisibilityParentFingerprint.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object SetPivotBarVisibilityParentFingerprint : MethodFingerprint( + parameters = listOf("Z"), + strings = listOf("FEnotifications_inbox") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt new file mode 100644 index 000000000..dcad8f43a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/bytecode/patch/HideShortsComponentsPatch.kt @@ -0,0 +1,146 @@ +package app.revanced.patches.youtube.layout.hide.shorts.bytecode.patch + +import app.revanced.extensions.findIndexForIdResource +import app.revanced.extensions.injectHideViewCall +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.youtube.layout.hide.shorts.annotations.HideShortsComponentsCompatibility +import app.revanced.patches.youtube.layout.hide.shorts.bytecode.fingerprints.* +import app.revanced.patches.youtube.layout.hide.shorts.resource.patch.HideShortsComponentsResourcePatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction + +@Patch +@DependsOn( + [ + IntegrationsPatch::class, + LithoFilterPatch::class, + HideShortsComponentsResourcePatch::class, + ResourceMappingPatch::class + ] +) +@Name("hide-shorts-components") +@Description("Hides components from YouTube Shorts.") +@HideShortsComponentsCompatibility +@Version("0.0.1") +class HideShortsComponentsPatch : BytecodePatch( + listOf( + CreateShortsButtonsFingerprint, + ReelConstructorFingerprint, + BottomNavigationBarFingerprint, + RenderBottomNavigationBarParentFingerprint, + SetPivotBarVisibilityParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + // region Hide the Shorts shelf. + + ReelConstructorFingerprint.result?.let { + it.mutableMethod.apply { + val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 + val viewRegister = instruction<TwoRegisterInstruction>(insertIndex).registerA + + injectHideViewCall( + insertIndex, + viewRegister, + CLASS_DESCRIPTOR, + "hideShortsShelf" + ) + } + } ?: return ReelConstructorFingerprint.toErrorResult() + + // endregion + + // region Hide the Shorts buttons. + + // Some Shorts buttons are views, hide them by setting their visibility to GONE. + CreateShortsButtonsFingerprint.result?.let { + ShortsButtons.values().forEach { button -> button.injectHideCall(it.mutableMethod) } + } ?: return CreateShortsButtonsFingerprint.toErrorResult() + + // endregion + + // region Hide the navigation bar. + + // Hook to get the pivotBar view. + SetPivotBarVisibilityParentFingerprint.result?.let { + if (!SetPivotBarVisibilityFingerprint.resolve(context, it.classDef)) + throw SetPivotBarVisibilityFingerprint.toErrorResult() + + SetPivotBarVisibilityFingerprint.result!!.let { result -> + result.mutableMethod.apply { + val checkCastIndex = result.scanResult.patternScanResult!!.endIndex + val viewRegister = instruction<OneRegisterInstruction>(checkCastIndex).registerA + addInstruction( + checkCastIndex + 1, + "sput-object v$viewRegister, $CLASS_DESCRIPTOR->pivotBar:" + + "Lcom/google/android/libraries/youtube/rendering/ui/pivotbar/PivotBar;" + ) + } + } + } ?: return SetPivotBarVisibilityParentFingerprint.toErrorResult() + + // Hook to hide the navigation bar when Shorts are being played. + RenderBottomNavigationBarParentFingerprint.result?.let { + if (!RenderBottomNavigationBarFingerprint.resolve(context, it.classDef)) + throw RenderBottomNavigationBarFingerprint.toErrorResult() + + RenderBottomNavigationBarFingerprint.result!!.mutableMethod.apply { + addInstruction(0, "invoke-static { }, $CLASS_DESCRIPTOR->hideNavigationBar()V") + } + } ?: return RenderBottomNavigationBarParentFingerprint.toErrorResult() + + // Required to prevent a black bar from appearing at the bottom of the screen. + BottomNavigationBarFingerprint.result?.let { + it.mutableMethod.apply { + val moveResultIndex = it.scanResult.patternScanResult!!.startIndex + val viewRegister = instruction<OneRegisterInstruction>(moveResultIndex).registerA + val insertIndex = moveResultIndex + 1 + + addInstruction( + insertIndex, + "invoke-static { v$viewRegister }, $CLASS_DESCRIPTOR->" + + "hideNavigationBar(Landroid/view/View;)Landroid/view/View;" + ) + } + } ?: return BottomNavigationBarFingerprint.toErrorResult() + + // endregion + + return PatchResultSuccess() + } + + private companion object { + private const val CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/components/ShortsFilter;" + + private enum class ShortsButtons(private val resourceName: String, private val methodName: String) { + COMMENTS("reel_dyn_comment", "hideShortsCommentsButton"), + REMIX("reel_dyn_remix", "hideShortsRemixButton"), + SHARE("reel_dyn_share", "hideShortsShareButton"); + + fun injectHideCall(method: MutableMethod) { + val referencedIndex = method.findIndexForIdResource(resourceName) + + val setIdIndex = referencedIndex + 1 + val viewRegister = method.instruction<FiveRegisterInstruction>(setIdIndex).registerC + method.injectHideViewCall(setIdIndex, viewRegister, CLASS_DESCRIPTOR, methodName) + } + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt new file mode 100644 index 000000000..29e3d149e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/shorts/resource/patch/HideShortsComponentsResourcePatch.kt @@ -0,0 +1,89 @@ +package app.revanced.patches.youtube.layout.hide.shorts.resource.patch + +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch + +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +@Version("0.0.1") +class HideShortsComponentsResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( + PreferenceScreen( + "revanced_shorts", + StringResource("revanced_shorts_title", "Shorts components"), + listOf( + SwitchPreference( + "revanced_hide_shorts", + StringResource("revanced_hide_shorts_enabled_title", "Hide shorts"), + StringResource("revanced_hide_shorts_on", "Shorts are hidden"), + StringResource("revanced_hide_shorts_off", "Shorts are shown") + ), + SwitchPreference( + "revanced_hide_shorts_join_button", + StringResource("revanced_hide_shorts_join_button_title", "Hide join button"), + StringResource("revanced_hide_shorts_join_button_on", "Join button is hidden"), + StringResource("revanced_hide_shorts_join_button_off", "Join button is shown") + ), + SwitchPreference( + "revanced_hide_shorts_subscribe_button", + StringResource("revanced_hide_shorts_subscribe_button_title", "Hide subscribe button"), + StringResource("revanced_hide_shorts_subscribe_button_on", "Subscribe button is hidden"), + StringResource("revanced_hide_shorts_subscribe_button_off", "Subscribe button is shown") + ), + SwitchPreference( + "revanced_hide_shorts_thanks_button", + StringResource("revanced_hide_shorts_thanks_button_title", "Hide thanks button"), + StringResource("revanced_hide_shorts_thanks_button_on", "Thanks button is hidden"), + StringResource("revanced_hide_shorts_thanks_button_off", "Thanks button is shown") + ), + SwitchPreference( + "revanced_hide_shorts_comments_button", + StringResource("revanced_hide_shorts_comments_button_title", "Hide comments button"), + StringResource("revanced_hide_shorts_comments_button_on", "Comments button is hidden"), + StringResource("revanced_hide_shorts_comments_button_off", "Comments button is shown") + ), + SwitchPreference( + "revanced_hide_shorts_remix_button", + StringResource("revanced_hide_shorts_remix_button_title", "Hide remix button"), + StringResource("revanced_hide_shorts_remix_button_on", "Remix button is hidden"), + StringResource("revanced_hide_shorts_remix_button_off", "Remix button is shown") + ), + SwitchPreference( + "revanced_hide_shorts_share_button", + StringResource("revanced_hide_shorts_share_button_title", "Hide share button"), + StringResource("revanced_hide_shorts_share_button_on", "Share button is hidden"), + StringResource("revanced_hide_shorts_share_button_off", "Share button is shown") + ), + SwitchPreference( + "revanced_hide_shorts_navigation_bar", + StringResource("revanced_hide_shorts_navigation_bar_title", "Hide navigation bar"), + StringResource("revanced_hide_shorts_navigation_bar_on", "Navigation bar is hidden"), + StringResource("revanced_hide_shorts_navigation_bar_off", "Navigation bar is shown") + ), + ), + StringResource("revanced_shorts_summary", "Manage the visibility of Shorts components") + ) + ) + + fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id + + reelMultipleItemShelfId = "reel_multiple_items_shelf".getId() + reelPlayerRightLargeIconSize = "reel_player_right_large_icon_size".getId() + + return PatchResultSuccess() + } + + companion object { + var reelMultipleItemShelfId: Long = -1 + var reelPlayerRightLargeIconSize = -1L + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt index 765783005..c3f3c7776 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/annotations/HideTimeCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.hide.time.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class HideTimeCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/patch/HideTimestampPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/patch/HideTimestampPatch.kt index e30f8cb5a..635578a64 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/patch/HideTimestampPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/time/patch/HideTimestampPatch.kt @@ -33,7 +33,6 @@ class HideTimestampPatch : BytecodePatch( SwitchPreference( "revanced_hide_timestamp", StringResource("revanced_hide_timestamp_title", "Hide video timestamp"), - false, StringResource("revanced_hide_timestamp_summary_on", "Timestamp is hidden"), StringResource("revanced_hide_timestamp_summary_off", "Timestamp is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt new file mode 100644 index 000000000..9eba5cc7c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchInVRCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.watchinvr.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class WatchInVRCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchinVRCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchinVRCompatibility.kt deleted file mode 100644 index b810666de..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/annotations/WatchinVRCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.watchinvr.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class WatchinVRCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/patch/WatchInVRPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/patch/WatchInVRPatch.kt index 84e8d8d94..89b278620 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/patch/WatchInVRPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watchinvr/patch/WatchInVRPatch.kt @@ -12,7 +12,7 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.layout.hide.watchinvr.annotations.WatchinVRCompatibility +import app.revanced.patches.youtube.layout.hide.watchinvr.annotations.WatchInVRCompatibility import app.revanced.patches.youtube.layout.hide.watchinvr.fingerprints.WatchInVRFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch @@ -21,7 +21,7 @@ import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch @DependsOn([IntegrationsPatch::class, SettingsPatch::class]) @Name("hide-watch-in-vr") @Description("Hides the option to watch in VR from the player settings flyout panel.") -@WatchinVRCompatibility +@WatchInVRCompatibility @Version("0.0.1") class WatchInVRPatch : BytecodePatch( listOf( @@ -33,7 +33,6 @@ class WatchInVRPatch : BytecodePatch( SwitchPreference( "revanced_hide_watch_in_vr", StringResource("revanced_hide_watch_in_vr_title", "Hide VR setting"), - false, StringResource("revanced_hide_watch_in_vr_summary_on", "VR setting is hidden"), StringResource("revanced_hide_watch_in_vr_summary_off", "VR setting is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt new file mode 100644 index 000000000..8d11da21a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWatermarkCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.hide.watermark.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HideWatermarkCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt deleted file mode 100644 index fd691647d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/annotations/HideWaterwarkCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.layout.hide.watermark.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class HideWatermarkCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/patch/HideWatermarkPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/patch/HideWatermarkPatch.kt index f149f3cf6..c6c2b3b06 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/patch/HideWatermarkPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/hide/watermark/patch/HideWatermarkPatch.kt @@ -37,7 +37,6 @@ class HideWatermarkPatch : BytecodePatch( SwitchPreference( "revanced_hide_video_watermark", StringResource("revanced_hide_video_watermark_title", "Hide creator watermark on videos"), - true, StringResource("revanced_hide_video_watermark_summary_on", "Watermark is hidden"), StringResource("revanced_hide_video_watermark_summary_off", "Watermark is shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt deleted file mode 100644 index 542e4b32f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.layout.oldqualitylayout.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class OldQualityLayoutCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt deleted file mode 100644 index 4abb688e9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object QualityMenuViewInflateFingerprint : MethodFingerprint( - "L", AccessFlags.FINAL or AccessFlags.PUBLIC, listOf("L", "L", "L"), listOf( - Opcode.INVOKE_SUPER, - Opcode.CONST, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.CONST_STRING, - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt index 24b1ca363..86a2865c2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/annotations/FullscreenPanelsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.panels.fullscreen.remove.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class FullscreenPanelsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/fingerprints/FullscreenViewAdderParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/fingerprints/FullscreenViewAdderParentFingerprint.kt index 6184eb0c2..601e62b83 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/fingerprints/FullscreenViewAdderParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/fingerprints/FullscreenViewAdderParentFingerprint.kt @@ -14,5 +14,7 @@ object FullscreenViewAdderParentFingerprint : MethodFingerprint( Opcode.CONST_4, Opcode.INVOKE_VIRTUAL, ), - customFingerprint = { it.definingClass.endsWith("FullscreenEngagementPanelOverlay;") } + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("FullscreenEngagementPanelOverlay;") + } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/patch/FullscreenPanelsRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/patch/FullscreenPanelsRemoverPatch.kt index 3939bdcac..791273ad6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/patch/FullscreenPanelsRemoverPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/fullscreen/remove/patch/FullscreenPanelsRemoverPatch.kt @@ -37,7 +37,6 @@ class FullscreenPanelsRemoverPatch : BytecodePatch( SwitchPreference( "revanced_hide_fullscreen_panels", StringResource("revanced_hide_fullscreen_panels_title", "Hide fullscreen panels"), - true, StringResource("revanced_hide_fullscreen_panels_summary_on", "Fullscreen panels are hidden"), StringResource("revanced_hide_fullscreen_panels_summary_off", "Fullscreen panels are shown") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt index c37a86b5f..c05d454b4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/annotations/PlayerPopupPanelsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.panels.popup.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class PlayerPopupPanelsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/fingerprints/EngagementPanelControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/fingerprints/EngagementPanelControllerFingerprint.kt index c09853574..a45ae6093 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/fingerprints/EngagementPanelControllerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/fingerprints/EngagementPanelControllerFingerprint.kt @@ -9,7 +9,7 @@ import org.jf.dexlib2.AccessFlags @FuzzyPatternScanMethod(3) object EngagementPanelControllerFingerprint : MethodFingerprint( returnType = "L", - access = AccessFlags.PRIVATE or AccessFlags.FINAL, + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, strings = listOf( "EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.", "[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called." diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/patch/PlayerPopupPanelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/patch/PlayerPopupPanelsPatch.kt index a8dabc9ca..bf2447c4e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/patch/PlayerPopupPanelsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/panels/popup/patch/PlayerPopupPanelsPatch.kt @@ -32,11 +32,10 @@ class PlayerPopupPanelsPatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( SwitchPreference( - "revanced_player_popup_panels_enabled", - StringResource("revanced_player_popup_panels_title", "Disable player popup panels"), - false, - StringResource("revanced_player_popup_panels_summary_on", "Player popup panels are disabled"), - StringResource("revanced_player_popup_panels_summary_off", "Player popup panels are enabled") + "revanced_hide_player_popup_panels", + StringResource("revanced_hide_player_popup_panels_title", "Hide player popup panels"), + StringResource("revanced_hide_player_popup_panels_summary_on", "Player popup panels are hidden"), + StringResource("revanced_hide_player_popup_panels_summary_off", "Player popup panels are shown") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt index 747d0a947..aa0f3fcc5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt @@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.returnyoutubedislike.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility([Package("com.google.android.youtube", arrayOf("18.15.40", "18.16.37"))]) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class ReturnYouTubeDislikeCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikesOldLayoutTextViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikesOldLayoutTextViewFingerprint.kt index 29ab1564d..7fe768162 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikesOldLayoutTextViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikesOldLayoutTextViewFingerprint.kt @@ -10,7 +10,7 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction object DislikesOldLayoutTextViewFingerprint : MethodFingerprint( returnType = "V", parameters = listOf("L"), - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf( Opcode.CONST, // resource identifier register Opcode.INVOKE_VIRTUAL, @@ -19,7 +19,7 @@ object DislikesOldLayoutTextViewFingerprint : MethodFingerprint( Opcode.IF_NEZ, // textview register Opcode.GOTO, ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == ReturnYouTubeDislikeResourcePatch.oldUIDislikeId diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt deleted file mode 100644 index f4e6f7801..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextComponentParentFingerprint.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object ShortsTextComponentParentFingerprint : MethodFingerprint( - returnType = "V", - parameters = listOf("L", "L"), - opcodes = listOf( - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.GOTO, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID, - Opcode.IGET_OBJECT, - Opcode.CHECK_CAST, - Opcode.IGET_BOOLEAN, - Opcode.IF_EQZ, - Opcode.INVOKE_STATIC - ) -) \ 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 new file mode 100644 index 000000000..9d5c2ec2a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/ShortsTextViewFingerprint.kt @@ -0,0 +1,30 @@ +package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object ShortsTextViewFingerprint : MethodFingerprint( + returnType = "V", + parameters = listOf("L", "L"), + opcodes = listOf( + Opcode.INVOKE_SUPER, // first instruction of method + Opcode.IF_NEZ, + Opcode.RETURN_VOID, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.SGET_OBJECT, // insertion point, must be after constructor call to parent class + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.CONST_4, + Opcode.IF_EQ, + Opcode.CONST_4, + Opcode.IF_EQ, + Opcode.RETURN_VOID, + Opcode.IGET_OBJECT, // TextView field + Opcode.CHECK_CAST, + Opcode.IGET_BOOLEAN, // boolean field + ) +) \ No newline at end of file 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 2385aa904..199f14889 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 @@ -10,11 +10,10 @@ import org.jf.dexlib2.Opcode */ object TextComponentAtomicReferenceFingerprint : MethodFingerprint( returnType = "L", - access = AccessFlags.PROTECTED or AccessFlags.FINAL, + accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, parameters = listOf("L"), opcodes = listOf( - Opcode.MOVE_OBJECT, // available unused register - Opcode.MOVE_OBJECT_FROM16, + Opcode.MOVE_OBJECT_FROM16, // available unused register Opcode.MOVE_OBJECT_FROM16, Opcode.MOVE_OBJECT_FROM16, Opcode.MOVE_OBJECT_FROM16, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt index ca29b8eee..5f5c18844 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentConstructorFingerprint.kt @@ -6,6 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags object TextComponentConstructorFingerprint : MethodFingerprint( - access = AccessFlags.CONSTRUCTOR or AccessFlags.PRIVATE, + accessFlags = AccessFlags.CONSTRUCTOR or AccessFlags.PRIVATE, strings = listOf("TextComponent") ) \ No newline at end of file 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 1a23e7046..eee7ab2a2 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 @@ -10,7 +10,7 @@ import org.jf.dexlib2.Opcode */ object TextComponentContextFingerprint : MethodFingerprint( returnType = "L", - access = AccessFlags.PROTECTED or AccessFlags.FINAL, + accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL, parameters = listOf("L"), opcodes = listOf( Opcode.IGET_OBJECT, // conversion context field name diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt index 1686c7996..b75fddfcf 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt @@ -5,7 +5,6 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.extensions.MethodFingerprintExtensions.name import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions @@ -19,14 +18,12 @@ import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.* import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch -import org.jf.dexlib2.builder.instruction.BuilderInstruction35c +import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction @@ -48,7 +45,7 @@ import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction class ReturnYouTubeDislikePatch : BytecodePatch( listOf( TextComponentConstructorFingerprint, - ShortsTextComponentParentFingerprint, + ShortsTextViewFingerprint, DislikesOldLayoutTextViewFingerprint, LikeFingerprint, DislikeFingerprint, @@ -102,18 +99,21 @@ class ReturnYouTubeDislikePatch : BytecodePatch( val atomicReferenceStartIndex = TextComponentAtomicReferenceFingerprint.result!! .scanResult.patternScanResult!!.startIndex + val insertIndex = atomicReferenceStartIndex + 7 + textComponentContextFingerprintResult.mutableMethod.apply { // Get the conversion context obfuscated field name, and the registers for the AtomicReference and CharSequence val conversionContextFieldReference = - (instruction(conversionContextIndex) as ReferenceInstruction).reference + instruction<ReferenceInstruction>(conversionContextIndex).reference + // any free register val contextRegister = - (instruction(atomicReferenceStartIndex) as TwoRegisterInstruction).registerB - val atomicReferenceRegister = - (instruction(atomicReferenceStartIndex + 5) as FiveRegisterInstruction).registerC + instruction<TwoRegisterInstruction>(atomicReferenceStartIndex).registerB - val insertIndex = atomicReferenceStartIndex + 8 - val moveCharSequenceInstruction = instruction(insertIndex) as TwoRegisterInstruction + val atomicReferenceRegister = + instruction<FiveRegisterInstruction>(atomicReferenceStartIndex + 4).registerC + + val moveCharSequenceInstruction = instruction<TwoRegisterInstruction>(insertIndex) val charSequenceRegister = moveCharSequenceInstruction.registerB // Insert as first instructions at the control flow label. @@ -134,35 +134,40 @@ class ReturnYouTubeDislikePatch : BytecodePatch( // region Hook for Short videos. - ShortsTextComponentParentFingerprint.result?.let { - context - .toMethodWalker(it.method) - .nextMethod(it.scanResult.patternScanResult!!.endIndex, true) - .getMethod().let { method -> - with(method as MutableMethod) { - // After walking, verify the found method is what's expected. - if (returnType != ("Ljava/lang/CharSequence;") || parameterTypes.size != 1) - return PatchResultError("Method signature did not match: $this $parameterTypes") + ShortsTextViewFingerprint.result?.let { + it.mutableMethod.apply { + val patternResult = it.scanResult.patternScanResult!! - val insertIndex = implementation!!.instructions.size - 1 - val spannedParameterRegister = (instruction(insertIndex) as OneRegisterInstruction).registerA - val parameter = (instruction(insertIndex - 2) as BuilderInstruction35c).reference + // If the field is true, the TextView is for a dislike button. + val isDisLikesBooleanReference = instruction<ReferenceInstruction>(patternResult.endIndex).reference - if (!parameter.toString().endsWith("Landroid/text/Spanned;")) - return PatchResultError("Method signature parameter did not match: $parameter") + val textViewFieldReference = // Like/Dislike button TextView field + instruction<ReferenceInstruction>(patternResult.endIndex - 2).reference - insertShorts(insertIndex, spannedParameterRegister) - } - } - - // Additional hook, called after user dislikes. - with(it.mutableMethod) { - val insertIndex = it.scanResult.patternScanResult!!.startIndex + 2 - val overwriteRegister = (implementation!!.instructions.elementAt(insertIndex - 1) - as OneRegisterInstruction).registerA - insertShorts(insertIndex, overwriteRegister) + // Check if the hooked TextView object is that of the dislike button. + // If RYD is disabled, or the TextView object is not that of the dislike button, the execution flow is not interrupted. + // Otherwise, the TextView object is modified, and the execution flow is interrupted to prevent it from being changed afterward. + val insertIndex = patternResult.startIndex + 6 + addInstructions( + insertIndex, """ + # Check, if the TextView is for a dislike button + iget-boolean v0, p0, $isDisLikesBooleanReference + if-eqz v0, :is_like + + # Hook the TextView, if it is for the dislike button + iget-object v0, p0, $textViewFieldReference + invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setShortsDislikes(Landroid/view/View;)Z + move-result v0 + if-eqz v0, :ryd_disabled + return-void + + :is_like + :ryd_disabled + nop + """ + ) } - } ?: return ShortsTextComponentParentFingerprint.toErrorResult() + } ?: return ShortsTextViewFingerprint.toErrorResult() // endregion @@ -171,9 +176,12 @@ class ReturnYouTubeDislikePatch : BytecodePatch( DislikesOldLayoutTextViewFingerprint.result?.let { it.mutableMethod.apply { val startIndex = it.scanResult.patternScanResult!!.startIndex - val resourceIdentifierRegister = (instruction(startIndex) as OneRegisterInstruction).registerA - val textViewRegister = (instruction(startIndex + 4) as OneRegisterInstruction).registerA - addInstruction(startIndex + 4, + + val resourceIdentifierRegister = instruction<OneRegisterInstruction>(startIndex).registerA + val textViewRegister = instruction<OneRegisterInstruction>(startIndex + 4).registerA + + addInstruction( + startIndex + 4, "invoke-static {v$resourceIdentifierRegister, v$textViewRegister}, $INTEGRATIONS_CLASS_DESCRIPTOR->setOldUILayoutDislikes(ILandroid/widget/TextView;)V" ) } @@ -195,14 +203,5 @@ class ReturnYouTubeDislikePatch : BytecodePatch( DISLIKE(-1), REMOVE_LIKE(0) } - - private fun MutableMethod.insertShorts(index: Int, register: Int) { - addInstructions( - index, """ - invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->onShortsComponentCreated(Landroid/text/Spanned;)Landroid/text/Spanned; - move-result-object v$register - """ - ) - } } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt index 41e8eb34a..866890cbc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt @@ -26,16 +26,11 @@ class ReturnYouTubeDislikeResourcePatch : ResourcePatch { } override fun execute(context: ResourceContext): PatchResult { - val youtubePackage = "com.google.android.youtube" SettingsPatch.addPreference( Preference( StringResource("revanced_ryd_settings_title", "Return YouTube Dislike"), - Preference.Intent( - youtubePackage, - "ryd_settings", - "com.google.android.libraries.social.licenses.LicenseActivity" - ), StringResource("revanced_ryd_settings_summary", "Settings for Return YouTube Dislike"), + SettingsPatch.createReVancedSettingsIntent("ryd_settings") ) ) // merge strings diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt index 33672c81c..75d3373ec 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/annotations/WideSearchbarCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.searchbar.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class WideSearchbarCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt index 97cb02215..f0a823398 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/fingerprints/SetWordmarkHeaderFingerprint.kt @@ -18,5 +18,5 @@ object SetWordmarkHeaderFingerprint : MethodFingerprint( Opcode.CONST, Opcode.INVOKE_STATIC, ), - customFingerprint = { methodDef -> methodDef.parameterTypes.first() == "Landroid/widget/ImageView;" } + customFingerprint = { methodDef, _ -> methodDef.parameterTypes.first() == "Landroid/widget/ImageView;" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/patch/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/patch/WideSearchbarPatch.kt index 62bd87fe9..2894e8d63 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/patch/WideSearchbarPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/searchbar/patch/WideSearchbarPatch.kt @@ -38,7 +38,6 @@ class WideSearchbarPatch : BytecodePatch( SwitchPreference( "revanced_wide_searchbar", StringResource("revanced_wide_searchbar_enabled_title", "Enable wide search bar"), - false, StringResource("revanced_wide_searchbar_summary_on", "Wide search bar is enabled"), StringResource("revanced_wide_searchbar_summary_off", "Wide search bar is disabled") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/annotations/SeekbarColorCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/annotations/SeekbarColorCompatibility.kt new file mode 100644 index 000000000..845bbff94 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/annotations/SeekbarColorCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.layout.seekbar.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube")]) +@Target(AnnotationTarget.CLASS) +internal annotation class SeekbarColorCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/fingerprints/CreateDarkThemeSeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/fingerprints/CreateDarkThemeSeekbarFingerprint.kt new file mode 100644 index 000000000..89aec9b6f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/fingerprints/CreateDarkThemeSeekbarFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.layout.seekbar.resource.SeekbarColorResourcePatch +import app.revanced.util.patch.indexOfFirstConstantInstruction +import org.jf.dexlib2.AccessFlags + +object CreateDarkThemeSeekbarFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + customFingerprint = { method, _ -> + method.indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId) != -1 + && method.indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarPlayedNotHighlightedColorId) != -1 + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/SetSeekbarClickedColorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/fingerprints/SetSeekbarClickedColorFingerprint.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/SetSeekbarClickedColorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/fingerprints/SetSeekbarClickedColorFingerprint.kt index 0237c1ec3..abae290d7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/SetSeekbarClickedColorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/fingerprints/SetSeekbarClickedColorFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints +package app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/patch/SeekbarColorBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/patch/SeekbarColorBytecodePatch.kt new file mode 100644 index 000000000..752f23afa --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/bytecode/patch/SeekbarColorBytecodePatch.kt @@ -0,0 +1,85 @@ +package app.revanced.patches.youtube.layout.seekbar.bytecode.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.layout.seekbar.annotations.SeekbarColorCompatibility +import app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint +import app.revanced.patches.youtube.layout.seekbar.bytecode.fingerprints.SetSeekbarClickedColorFingerprint +import app.revanced.patches.youtube.layout.theme.bytecode.patch.LithoColorHookPatch +import app.revanced.patches.youtube.layout.theme.bytecode.patch.LithoColorHookPatch.Companion.lithoColorOverrideHook +import app.revanced.patches.youtube.layout.seekbar.resource.SeekbarColorResourcePatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.util.patch.indexOfFirstConstantInstruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction + +@Description("Hide or set a custom seekbar color") +@DependsOn([IntegrationsPatch::class, LithoColorHookPatch::class, SeekbarColorResourcePatch::class]) +@SeekbarColorCompatibility +@Version("0.0.1") +class SeekbarColorBytecodePatch : BytecodePatch( + listOf(CreateDarkThemeSeekbarFingerprint, SetSeekbarClickedColorFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + CreateDarkThemeSeekbarFingerprint.result?.mutableMethod?.apply { + var registerIndex = indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId) + 2 + var colorRegister = (instruction(registerIndex) as OneRegisterInstruction).registerA + addInstructions( + registerIndex + 1, + """ + invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue(I)I + move-result v$colorRegister + """ + ) + + registerIndex = indexOfFirstConstantInstruction(SeekbarColorResourcePatch.inlineTimeBarPlayedNotHighlightedColorId) + 2 + colorRegister = (instruction(registerIndex) as OneRegisterInstruction).registerA + addInstructions( + registerIndex + 1, + """ + invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue(I)I + move-result v$colorRegister + """ + ) + } ?: return CreateDarkThemeSeekbarFingerprint.toErrorResult() + + SetSeekbarClickedColorFingerprint.result?.let { result -> + result.mutableMethod.let { + val setColorMethodIndex = result.scanResult.patternScanResult!!.startIndex + 1 + val method = context + .toMethodWalker(it) + .nextMethod(setColorMethodIndex, true) + .getMethod() as MutableMethod + + method.apply { + val colorRegister = (method.instruction(0) as TwoRegisterInstruction).registerA + addInstructions( + 0, + """ + invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorOverride(I)I + move-result v$colorRegister + """ + ) + } + } + } ?: return SetSeekbarClickedColorFingerprint.toErrorResult() + + lithoColorOverrideHook(INTEGRATIONS_CLASS_DESCRIPTOR, "getSeekbarColorOverride") + + return PatchResultSuccess() + } + + private companion object { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/SeekbarColorPatch;" + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/resource/SeekbarColorResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/resource/SeekbarColorResourcePatch.kt new file mode 100644 index 000000000..a6bc89a84 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/resource/SeekbarColorResourcePatch.kt @@ -0,0 +1,45 @@ +package app.revanced.patches.youtube.layout.seekbar.resource + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import org.w3c.dom.Element + +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +class SeekbarColorResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + // Edit theme colors via bytecode. + // For that the resource id is used in a bytecode patch to change the color. + + val seekbarErrorMessage = "Could not find seekbar resource" + inlineTimeBarColorizedBarPlayedColorDarkId = ResourceMappingPatch.resourceMappings + .find { it.name == "inline_time_bar_colorized_bar_played_color_dark" }?.id + ?: return PatchResultError(seekbarErrorMessage) + inlineTimeBarPlayedNotHighlightedColorId = ResourceMappingPatch.resourceMappings + .find { it.name == "inline_time_bar_played_not_highlighted_color" }?.id + ?: return PatchResultError(seekbarErrorMessage) + + // Edit the resume playback drawable and replace the progress bar with a custom drawable + context.xmlEditor["res/drawable/resume_playback_progressbar_drawable.xml"].use { editor -> + val layerList = editor.file.getElementsByTagName("layer-list").item(0) as Element + val progressNode = layerList.getElementsByTagName("item").item(1) as Element + if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) { + return PatchResultError("Could not find progress bar") + } + val scaleNode = progressNode.getElementsByTagName("scale").item(0) as Element + val shapeNode = scaleNode.getElementsByTagName("shape").item(0) as Element + val replacementNode = editor.file.createElement( + "app.revanced.integrations.patches.theme.ProgressBarDrawable") + scaleNode.replaceChild(replacementNode, shapeNode) + } + + return PatchResultSuccess() + } + + companion object { + internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L + internal var inlineTimeBarPlayedNotHighlightedColorId = -1L + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt index f1d59fb51..f805334ff 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt @@ -3,8 +3,6 @@ package app.revanced.patches.youtube.layout.sponsorblock.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package("com.google.android.youtube", arrayOf("18.08.37", "18.15.40", "18.16.37"))] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class SponsorBlockCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ControlsOverlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ControlsOverlayFingerprint.kt new file mode 100644 index 000000000..a537a12f2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ControlsOverlayFingerprint.kt @@ -0,0 +1,27 @@ +package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ControlsOverlayFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + parameters = listOf(), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, // R.id.inset_overlay_view_layout + Opcode.IPUT_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.NEW_INSTANCE, + ), + customFingerprint = { methodDef, _ -> + methodDef.definingClass == "Lcom/google/android/apps/youtube/app/player/overlay/YouTubeControlsOverlay;" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt deleted file mode 100644 index 975bdfe7a..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object PlayerOverlaysLayoutInitFingerprint : MethodFingerprint( - - customFingerprint = { methodDef -> methodDef.returnType.endsWith("YouTubePlayerOverlaysLayout;") } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt index 822484a89..9aa72efba 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.iface.reference.MethodReference object RectangleFieldInvalidatorFingerprint : MethodFingerprint( "V", - customFingerprint = custom@{ methodDef -> + customFingerprint = custom@{ methodDef, _ -> val instructions = methodDef.implementation?.instructions!! val instructionCount = instructions.count() diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt index 931fbfd56..84112ff82 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt @@ -8,6 +8,7 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch @@ -22,7 +23,7 @@ import app.revanced.patches.shared.fingerprints.SeekbarOnDrawFingerprint import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.AppendTimeFingerprint -import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.PlayerOverlaysLayoutInitFingerprint +import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.ControlsOverlayFingerprint import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.RectangleFieldInvalidatorFingerprint import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatFingerprint @@ -30,8 +31,8 @@ import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParen import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch +import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch +import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.* import org.jf.dexlib2.iface.instruction.formats.Instruction35c @@ -60,7 +61,7 @@ class SponsorBlockBytecodePatch : BytecodePatch( listOf( SeekbarFingerprint, AppendTimeFingerprint, - PlayerOverlaysLayoutInitFingerprint, + ControlsOverlayFingerprint, AutoRepeatParentFingerprint, ) ) { @@ -102,17 +103,18 @@ class SponsorBlockBytecodePatch : BytecodePatch( val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions /* - * Get the instance of the seekbar rectangle + * Get left and right of seekbar rectangle */ - for ((index, instruction) in seekbarMethodInstructions.withIndex()) { - if (instruction.opcode != Opcode.MOVE_OBJECT_FROM16) continue - seekbarMethod.addInstruction( - index + 1, - "invoke-static/range {p0 .. p0}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V" - ) - break + val moveRectangleToRegisterIndex = seekbarMethodInstructions.indexOfFirst { + it.opcode == Opcode.MOVE_OBJECT_FROM16 } + seekbarMethod.addInstruction( + moveRectangleToRegisterIndex + 1, + "invoke-static/range {p0 .. p0}, " + + "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V" + ) + for ((index, instruction) in seekbarMethodInstructions.withIndex()) { if (instruction.opcode != Opcode.INVOKE_STATIC) continue @@ -124,38 +126,15 @@ class SponsorBlockBytecodePatch : BytecodePatch( // set the thickness of the segment seekbarMethod.addInstruction( insertIndex, - "invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V" + "invoke-static {v${invokeInstruction.registerC}}, " + + "$INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V" ) break } - /* - * Set rectangle absolute left and right positions - */ - val drawRectangleInstructions = seekbarMethodInstructions.withIndex().filter { (_, instruction) -> - instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect" - }.map { (index, instruction) -> // TODO: improve code - index to (instruction as FiveRegisterInstruction).registerD - } - - val (indexRight, rectangleRightRegister) = drawRectangleInstructions[0] - val (indexLeft, rectangleLeftRegister) = drawRectangleInstructions[3] - - // order of operation is important here due to the code above which has to be improved - // the reason for that is that we get the index, add instructions and then the offset would be wrong - seekbarMethod.addInstruction( - indexLeft + 1, - "invoke-static {v$rectangleLeftRegister}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteLeft(Landroid/graphics/Rect;)V" - ) - seekbarMethod.addInstruction( - indexRight + 1, - "invoke-static {v$rectangleRightRegister}, $INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteRight(Landroid/graphics/Rect;)V" - ) - /* * Draw segment */ - // Find the drawCircle call and draw the segment before it for (i in seekbarMethodInstructions.size - 1 downTo 0) { val invokeInstruction = seekbarMethodInstructions[i] as? ReferenceInstruction ?: continue @@ -198,8 +177,8 @@ class SponsorBlockBytecodePatch : BytecodePatch( method.addInstructions( moveResultInstructionIndex + 1, // insert right after moving the view to the register and use that register """ - invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;)V - invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;)V + invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_CREATE_SEGMENT_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/View;)V + invoke-static {v$inflatedViewRegister}, $INTEGRATIONS_VOTING_BUTTON_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/View;)V """ ) } @@ -240,10 +219,16 @@ class SponsorBlockBytecodePatch : BytecodePatch( VideoInformationPatch.onCreateHook(INTEGRATIONS_SEGMENT_PLAYBACK_CONTROLLER_CLASS_DESCRIPTOR, "initialize") // initialize the sponsorblock view - PlayerOverlaysLayoutInitFingerprint.result!!.mutableMethod.addInstruction( - 6, // after inflating the view - "invoke-static {p0}, $INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->initialize(Ljava/lang/Object;)V" - ) + ControlsOverlayFingerprint.result?.let { + val startIndex = it.scanResult.patternScanResult!!.startIndex + it.mutableMethod.apply { + val frameLayoutRegister = (instruction(startIndex + 2) as OneRegisterInstruction).registerA + addInstruction( + startIndex + 3, + "invoke-static {v$frameLayoutRegister}, $INTEGRATIONS_SPONSORBLOCK_VIEW_CONTROLLER_CLASS_DESCRIPTOR->initialize(Landroid/view/ViewGroup;)V" + ) + } + } ?: return ControlsOverlayFingerprint.toErrorResult() // get rectangle field name RectangleFieldInvalidatorFingerprint.resolve(context, seekbarSignatureResult.classDef) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt index 7c59a9ace..c5b97a993 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt @@ -10,7 +10,6 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.shared.settings.preference.impl.Preference import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.util.resources.ResourceUtils import app.revanced.util.resources.ResourceUtils.copyResources @@ -18,22 +17,16 @@ import app.revanced.util.resources.ResourceUtils.copyXmlNode import app.revanced.util.resources.ResourceUtils.mergeStrings @Name("sponsorblock-resource-patch") -@SponsorBlockCompatibility @DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) @Version("0.0.1") class SponsorBlockResourcePatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { - val youtubePackage = "com.google.android.youtube" SettingsPatch.addPreference( Preference( - StringResource("sb_settings", "SponsorBlock"), - Preference.Intent( - youtubePackage, - "sponsorblock_settings", - "com.google.android.libraries.social.licenses.LicenseActivity" - ), + StringResource("revanced_sponsorblock_settings_title", "SponsorBlock"), StringResource("revanced_sponsorblock_settings_summary", "SponsorBlock related settings"), + SettingsPatch.createReVancedSettingsIntent("sponsorblock_settings") ) ) val classLoader = this.javaClass.classLoader diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt index 82d01af3f..c64f17745 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/annotations/SpoofAppVersionCompatibility.kt @@ -3,23 +3,7 @@ package app.revanced.patches.youtube.layout.spoofappversion.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class SpoofAppVersionCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt index add8947a6..2567f3fc1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/spoofappversion/bytecode/patch/SpoofAppVersionPatch.kt @@ -37,12 +37,12 @@ class SpoofAppVersionPatch : BytecodePatch( SwitchPreference( "revanced_spoof_app_version", StringResource("revanced_spoof_app_version_title", "Spoof app version"), - false, StringResource("revanced_spoof_app_version_summary_on", "Version spoofed"), StringResource("revanced_spoof_app_version_summary_off", "Version not spoofed"), StringResource("revanced_spoof_app_version_user_dialog_message", - "App version will be spoofed to an older version of YouTube. This will change the appearance of the app, but unknown side effects may occur." - + " If later turned off, the old UI may remain until you log out or clear the app data.") + "App version will be spoofed to an older version of YouTube." + + "\\n\\nThis will change the appearance and features of the app, but unknown side effects may occur." + + "\\n\\nIf later turned off, the old UI may remain until you log out or clear the app data.") ), ListPreference( "revanced_spoof_app_version_target", diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt index 88b5a9297..72b516851 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.layout.startupshortsreset.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class StartupShortsResetCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt index af2fae09c..8be60b6a9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt @@ -31,11 +31,10 @@ class DisableShortsOnStartupPatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( SwitchPreference( - "revanced_startup_shorts_player_enabled", - StringResource("revanced_startup_shorts_player_title", "Disable shorts player at app startup"), - false, - StringResource("revanced_startup_shorts_player_summary_on", "Shorts player is disabled at app startup"), - StringResource("revanced_startup_shorts_player_summary_off", "Shorts player is enabled at app startup") + "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") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt index 21e909201..ded1563ed 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt @@ -3,6 +3,6 @@ package app.revanced.patches.youtube.layout.tabletminiplayer.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility([Package("com.google.android.youtube", arrayOf("18.15.40", "18.16.37"))]) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class TabletMiniPlayerCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt index 51ef60315..26994af50 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt @@ -42,7 +42,6 @@ class TabletMiniPlayerPatch : BytecodePatch( SwitchPreference( "revanced_tablet_miniplayer", StringResource("revanced_tablet_miniplayer_title", "Enable tablet mini player"), - false, StringResource("revanced_tablet_miniplayer_summary_on", "Mini player is enabled"), StringResource("revanced_tablet_miniplayer_summary_off", "Mini player is disabled") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/CreateDarkThemeSeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/CreateDarkThemeSeekbarFingerprint.kt deleted file mode 100644 index 98baa9d69..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/CreateDarkThemeSeekbarFingerprint.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint.indexOfInstructionWithSeekbarId -import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.Method -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object CreateDarkThemeSeekbarFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - customFingerprint = { method -> method.indexOfInstructionWithSeekbarId != -1 }, -) { - /** - * The index of the instruction that loads the resource id of the seekbar. - */ - internal val Method.indexOfInstructionWithSeekbarId - get() = implementation?.let { - it.instructions.indexOfFirst { instruction -> - instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == ThemeResourcePatch.inlineTimeBarColorizedBarPlayedColorDarkId - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/LithoThemeFingerprint.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/LithoThemeFingerprint.kt index ba6e29cf5..ffb29604f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/fingerprints/LithoThemeFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.theme.fingerprints +package app.revanced.patches.youtube.layout.theme.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/LithoColorHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/LithoColorHookPatch.kt new file mode 100644 index 000000000..0568876ef --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/LithoColorHookPatch.kt @@ -0,0 +1,47 @@ +package app.revanced.patches.youtube.layout.theme.bytecode.patch + +import app.revanced.extensions.toErrorResult +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility +import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.LithoThemeFingerprint + +@Name("litho-color-hook") +@Description("Adds a hook to set color of Litho components.") +@ThemeCompatibility +@Version("0.0.1") +class LithoColorHookPatch : BytecodePatch(listOf(LithoThemeFingerprint)) { + override fun execute(context: BytecodeContext): PatchResult { + LithoThemeFingerprint.result?.let { + insertionIndex = it.scanResult.patternScanResult!!.endIndex - 1 + colorRegister = "p1" + insertionMethod = it.mutableMethod + } ?: return LithoThemeFingerprint.toErrorResult() + + return PatchResultSuccess() + } + companion object { + private var insertionIndex : Int = -1 + private lateinit var colorRegister : String + private lateinit var insertionMethod : MutableMethod + + internal fun lithoColorOverrideHook(targetMethodClass: String, targetMethodName: String) { + insertionMethod.addInstructions( + insertionIndex, + """ + invoke-static {$colorRegister}, $targetMethodClass->$targetMethodName(I)I + move-result $colorRegister + """ + ) + insertionIndex += 2 + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeBytecodePatch.kt index fbc8dcefa..1889ed7a8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeBytecodePatch.kt @@ -1,77 +1,58 @@ package app.revanced.patches.youtube.layout.theme.bytecode.patch -import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.* import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.layout.seekbar.bytecode.patch.SeekbarColorBytecodePatch import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility -import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint -import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.CreateDarkThemeSeekbarFingerprint.indexOfInstructionWithSeekbarId -import app.revanced.patches.youtube.layout.theme.bytecode.fingerprints.SetSeekbarClickedColorFingerprint import app.revanced.patches.youtube.layout.theme.resource.ThemeResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction @Patch @Name("theme") @Description("Applies a custom theme.") -@DependsOn([ThemeLithoComponentsPatch::class, ThemeResourcePatch::class, IntegrationsPatch::class]) +@DependsOn([LithoColorHookPatch::class, SeekbarColorBytecodePatch::class, ThemeResourcePatch::class]) @ThemeCompatibility @Version("0.0.1") -class ThemeBytecodePatch : BytecodePatch( - listOf(CreateDarkThemeSeekbarFingerprint, SetSeekbarClickedColorFingerprint) -) { +class ThemeBytecodePatch : BytecodePatch() { + override fun execute(context: BytecodeContext): PatchResult { - CreateDarkThemeSeekbarFingerprint.result?.let { - val putColorValueIndex = it.method.indexOfInstructionWithSeekbarId!! + 3 + LithoColorHookPatch.lithoColorOverrideHook(INTEGRATIONS_CLASS_DESCRIPTOR, "getValue") - it.mutableMethod.apply { - val overrideRegister = (instruction(putColorValueIndex) as TwoRegisterInstruction).registerA - - addInstructions( - putColorValueIndex, - """ - invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarColorValue()I - move-result v$overrideRegister - """ - ) - } - } ?: return CreateDarkThemeSeekbarFingerprint.toErrorResult() - - SetSeekbarClickedColorFingerprint.result?.let { result -> - result.mutableMethod.let { - val setColorMethodIndex = result.scanResult.patternScanResult!!.startIndex + 1 - val method = context - .toMethodWalker(it) - .nextMethod(setColorMethodIndex, true) - .getMethod() as MutableMethod - - method.apply { - val colorRegister = (method.instruction(0) as TwoRegisterInstruction).registerA - addInstructions( - 0, - """ - invoke-static { v$colorRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getSeekbarClickedColorValue(I)I - move-result v$colorRegister - """ - ) - } - } - } ?: return SetSeekbarClickedColorFingerprint.toErrorResult() return PatchResultSuccess() } - private companion object { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemePatch;" + companion object : OptionsContainer() { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemeLithoComponentsPatch;" + + var darkThemeBackgroundColor: String? by option( + PatchOption.StringOption( + key = "darkThemeBackgroundColor", + default = "@android:color/black", + title = "Background color for the dark theme", + description = "The background color of the dark theme. Can be a hex color or a resource reference.", + ) + ) + + var lightThemeBackgroundColor: String? by option( + PatchOption.StringOption( + key = "lightThemeBackgroundColor", + default = "@android:color/white", + title = "Background color for the light theme", + description = "The background color of the light theme. Can be a hex color or a resource reference.", + ) + ) + + var splashScreenBackgroundColor: String? by option( + PatchOption.StringOption( + key = "splashScreenBackgroundColor", + default = "@android:color/black", + title = "Background color for the splash screen", + description = "The background color of the splash screen. Can be a hex color or a resource reference.", + ) + ) } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeLithoComponentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeLithoComponentsPatch.kt deleted file mode 100644 index cfcf75ed0..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/bytecode/patch/ThemeLithoComponentsPatch.kt +++ /dev/null @@ -1,40 +0,0 @@ -package app.revanced.patches.youtube.layout.theme.bytecode.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility -import app.revanced.patches.youtube.layout.theme.fingerprints.LithoThemeFingerprint - -@Name("theme-litho-components") -@Description("Applies a custom theme to Litho components.") -@ThemeCompatibility -@Version("0.0.1") -class ThemeLithoComponentsPatch : BytecodePatch(listOf(LithoThemeFingerprint)) { - override fun execute(context: BytecodeContext): PatchResult { - LithoThemeFingerprint.result?.let { - it.mutableMethod.apply { - val patchIndex = it.scanResult.patternScanResult!!.endIndex - 1 - - addInstructions( - patchIndex, - """ - invoke-static {p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->getValue(I)I - move-result p1 - """ - ) - } - } ?: return LithoThemeFingerprint.toErrorResult() - return PatchResultSuccess() - } - - private companion object { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/theme/ThemeLithoComponentsPatch;" - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/resource/ThemeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/resource/ThemeResourcePatch.kt index 12d396093..a69278309 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/resource/ThemeResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/resource/ThemeResourcePatch.kt @@ -1,15 +1,18 @@ package app.revanced.patches.youtube.layout.theme.resource import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.shared.settings.preference.impl.InputType import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.TextPreference +import app.revanced.patches.youtube.layout.theme.bytecode.patch.ThemeBytecodePatch.Companion.darkThemeBackgroundColor +import app.revanced.patches.youtube.layout.theme.bytecode.patch.ThemeBytecodePatch.Companion.lightThemeBackgroundColor +import app.revanced.patches.youtube.layout.theme.bytecode.patch.ThemeBytecodePatch.Companion.splashScreenBackgroundColor import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources import org.w3c.dom.Element @DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) @@ -19,73 +22,88 @@ class ThemeResourcePatch : ResourcePatch { TextPreference( "revanced_seekbar_color", StringResource("revanced_seekbar_color_title", "Seekbar color"), - InputType.STRING, - "#ffff0000", StringResource( "revanced_seekbar_color_summary", - "The color of the seekbar for the dark theme." - ) + "The color of the seekbar" + ), + InputType.TEXT_CAP_CHARACTERS ), ) - // Edit theme colors via bytecode. - // For that the resource id is used in a bytecode patch to change the color. - - inlineTimeBarColorizedBarPlayedColorDarkId = ResourceMappingPatch.resourceMappings - .find { it.name == "inline_time_bar_colorized_bar_played_color_dark" }?.id - ?: return PatchResultError("Could not find seekbar resource") - - - val darkThemeBackgroundColor = darkThemeBackgroundColor!! - val lightThemeBackgroundColor = lightThemeBackgroundColor!! - // Edit theme colors via resources. context.xmlEditor["res/values/colors.xml"].use { editor -> val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element - for (i in 0 until resourcesNode.childNodes.length) { - val node = resourcesNode.childNodes.item(i) as? Element ?: continue + val children = resourcesNode.childNodes + for (i in 0 until children.length) { + val node = children.item(i) as? Element ?: continue node.textContent = when (node.getAttribute("name")) { "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3", "yt_black4", "yt_status_bar_background_dark", "material_grey_850" -> darkThemeBackgroundColor + ?: continue "yt_white1", "yt_white1_opacity95", "yt_white1_opacity98", "yt_white2", "yt_white3", "yt_white4", - -> lightThemeBackgroundColor + -> lightThemeBackgroundColor ?: continue else -> continue } } } - // Copy the resource file to change the splash screen color. - context.copyResources( - "theme", ResourceUtils.ResourceGroup("values-night-v31", "styles.xml") - ) + splashScreenBackgroundColor ?: return PatchResultSuccess() + + // Edit splash screen background color for Android 11 and below. + context.xmlEditor["res/values/styles.xml"].use { + val resourcesNode = it.file.getElementsByTagName("resources").item(0) as Element + + val children = resourcesNode.childNodes + for (i in 0 until children.length) { + val node = children.item(i) as? Element ?: continue + + if (node.tagName != "style") continue + + val name = node.getAttribute("name") + if (name != LAUNCHER_STYLE_NAME) continue + + it.file.createElement("item").apply { + setAttribute("name", "android:windowSplashScreenBackground") + textContent = splashScreenBackgroundColor + }.also(node::appendChild) + + break + } + } + + // Edit splash screen background color for Android 12+. + + // Add the splash screen background color to the colors.xml file. + context.xmlEditor["res/values/colors.xml"].use { + val resourcesNode = it.file.getElementsByTagName("resources").item(0) as Element + + it.file.createElement("color").apply { + setAttribute("name", COLOR_NAME) + setAttribute("category", "color") + textContent = splashScreenBackgroundColor + }.also(resourcesNode::appendChild) + } + + // Point to the splash screen background color. + context.xmlEditor["res/drawable/quantum_launchscreen_youtube.xml"].use { + val node = it.file.getElementsByTagName("layer-list").item(0) as Element + + val backgroundColorItem = node.childNodes.item(1) as Element + backgroundColorItem.apply { + setAttribute("android:drawable", "@color/$COLOR_NAME") + } + } return PatchResultSuccess() } - companion object : OptionsContainer() { - internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L - - var darkThemeBackgroundColor: String? by option( - PatchOption.StringOption( - key = "darkThemeBackgroundColor", - default = "@android:color/black", - title = "Background color for the dark theme", - description = "The background color of the dark theme. Can be a hex color or a resource reference.", - ) - ) - - var lightThemeBackgroundColor: String? by option( - PatchOption.StringOption( - key = "lightThemeBackgroundColor", - default = "@android:color/white", - title = "Background color for the light theme", - description = "The background color of the light theme. Can be a hex color or a resource reference.", - ) - ) + private companion object { + private const val LAUNCHER_STYLE_NAME = "Base.Theme.YouTube.Launcher" + private const val COLOR_NAME = "splash_background_color" } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt index ad3f149b7..ab04bfe8d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.autorepeat.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class AutoRepeatCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt index a16683b14..c784ba8a0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt @@ -8,5 +8,7 @@ object AutoRepeatFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), - customFingerprint = { methodDef -> methodDef.implementation!!.instructions.count() == 3 && methodDef.annotations.isEmpty()} + customFingerprint = { methodDef, _ -> + methodDef.implementation!!.instructions.count() == 3 && methodDef.annotations.isEmpty() + } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt index 38617967d..08b2798da 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt @@ -35,9 +35,8 @@ class AutoRepeatPatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.MISC.addPreferences( SwitchPreference( - "revanced_pref_auto_repeat", - StringResource("revanced_auto_repeat_enabled_title", "Enable auto-repeat"), - false, + "revanced_auto_repeat", + StringResource("revanced_auto_repeat_title", "Enable auto-repeat"), StringResource("revanced_auto_repeat_summary_on", "Auto-repeat is enabled"), StringResource("revanced_auto_repeat_summary_off", "Auto-repeat is disabled") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt index ef0dba238..d5f279458 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt @@ -26,43 +26,39 @@ class DebuggingPatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { SettingsPatch.PreferenceScreen.MISC.addPreferences( app.revanced.patches.shared.settings.preference.impl.PreferenceScreen( - "revanced_debug", - StringResource("revanced_debug_title", "Debugging"), + "revanced_debug_preference_screen", + StringResource("revanced_debug_preference_screen_title", "Debugging"), listOf( SwitchPreference( - "revanced_debug_enabled", - StringResource("revanced_debug_enabled_title", "Debug logging"), - false, + "revanced_debug", + StringResource("revanced_debug_title", "Debug logging"), StringResource("revanced_debug_summary_on", "Debug logs are enabled"), StringResource("revanced_debug_summary_off", "Debug logs are disabled") ), SwitchPreference( - "revanced_debug_stacktrace_enabled", + "revanced_debug_stacktrace", StringResource( - "revanced_debug_stacktrace_enabled_title", + "revanced_debug_stacktrace_title", "Log stack traces" ), - false, StringResource("revanced_debug_stacktrace_summary_on", "Debug logs include stack trace"), StringResource("revanced_debug_stacktrace_summary_off", "Debug logs do not include stack trace") ), SwitchPreference( - "revanced_debug_toast_on_error_enabled", + "revanced_debug_toast_on_error", StringResource( - "revanced_debug_toast_on_error_enabled_title", + "revanced_debug_toast_on_error_title", "Show toast on ReVanced error" ), - true, StringResource("revanced_debug_toast_on_error_summary_on", "Toast shown if error occurs"), StringResource("revanced_debug_toast_on_error_summary_off", "Toast not shown if error occurs"), StringResource("revanced_debug_toast_on_error_user_dialog_message", - "Turning off error toasts hides all ReVanced error notifications." + - " This includes hiding normal network connection timeouts, " + - "but also hides notification of any unexpected and more serious errors." + "Turning off error toasts hides all ReVanced error notifications." + + "\\n\\nYou will not be notified of any unexpected events." ) ), ), - StringResource("revanced_debug_summary", "Enable or disable debugging options") + StringResource("revanced_debug_preference_screen_summary", "Enable or disable debugging options") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt index f04329dab..8a470352b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/annotation/FixBackToExitGestureCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.fix.backtoexitgesture.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class FixBackToExitGestureCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt index 010fd65ca..06f039393 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/OnBackPressedFingerprint.kt @@ -7,7 +7,7 @@ object OnBackPressedFingerprint : MethodFingerprint( opcodes = listOf( Opcode.RETURN_VOID ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("WatchWhileActivity;") && methodDef.name == "onBackPressed" } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/RecyclerViewTopScrollingParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/RecyclerViewTopScrollingParentFingerprint.kt index 09964ba5f..0d4425b90 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/RecyclerViewTopScrollingParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/backtoexitgesture/fingerprints/RecyclerViewTopScrollingParentFingerprint.kt @@ -14,7 +14,7 @@ object RecyclerViewTopScrollingParentFingerprint : MethodFingerprint( Opcode.INVOKE_VIRTUAL, Opcode.NEW_INSTANCE ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.name == "<init>" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt new file mode 100644 index 000000000..13e9c51b5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/ClientSpoofCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.misc.fix.playback.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class ClientSpoofCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SubtitleWindowSettingsConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SubtitleWindowSettingsConstructorFingerprint.kt index 0cb104f24..f37201f86 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SubtitleWindowSettingsConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SubtitleWindowSettingsConstructorFingerprint.kt @@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object SubtitleWindowSettingsConstructorFingerprint : MethodFingerprint( parameters = listOf("I", "I", "I", "Z", "Z"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass == "Lcom/google/android/libraries/youtube/player/subtitles/model/SubtitleWindowSettings;" && methodDef.name == "<init>" } diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt similarity index 82% rename from src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt index f3cf363e3..5428c2a4d 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/UserAgentHeaderBuilderFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.misc.fix.spoof.fingerprints +package app.revanced.patches.youtube.misc.fix.playback.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/ClientSpoofPatch.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/ClientSpoofPatch.kt index 161f960ee..b06a4bfa0 100644 --- a/src/main/kotlin/app/revanced/patches/shared/misc/fix/spoof/patch/ClientSpoofPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/ClientSpoofPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.misc.fix.spoof.patch +package app.revanced.patches.youtube.misc.fix.playback.patch import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description @@ -12,9 +12,8 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.misc.fix.spoof.annotations.ClientSpoofCompatibility -import app.revanced.patches.shared.misc.fix.spoof.fingerprints.UserAgentHeaderBuilderFingerprint -import app.revanced.patches.youtube.misc.fix.playback.patch.SpoofSignatureVerificationPatch +import app.revanced.patches.youtube.misc.fix.playback.annotations.ClientSpoofCompatibility +import app.revanced.patches.youtube.misc.fix.playback.fingerprints.UserAgentHeaderBuilderFingerprint import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction @Patch @@ -30,7 +29,8 @@ class ClientSpoofPatch : BytecodePatch( UserAgentHeaderBuilderFingerprint.result?.let { result -> val insertIndex = result.scanResult.patternScanResult!!.endIndex result.mutableMethod.apply { - val packageNameRegister = (instruction(insertIndex) as FiveRegisterInstruction).registerD + val packageNameRegister = instruction<FiveRegisterInstruction>(insertIndex).registerD + addInstruction(insertIndex, "const-string v$packageNameRegister, \"$ORIGINAL_PACKAGE_NAME\"") } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt index 1f6d84c6d..db5229f94 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/SpoofSignatureVerificationPatch.kt @@ -21,7 +21,7 @@ import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SubtitleWindo import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch +import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Name("spoof-signature-verification") @@ -45,12 +45,11 @@ class SpoofSignatureVerificationPatch : BytecodePatch( SwitchPreference( "revanced_spoof_signature_verification", StringResource("revanced_spoof_signature_verification_title", "Spoof app signature"), - true, StringResource("revanced_spoof_signature_verification_summary_on", "App signature spoofed\\n\\n" + "Side effects include:\\n" + "• End screen cards are always hidden\\n" - + "• Download button may be hidden"), + + "• Downloading videos may not work"), StringResource("revanced_spoof_signature_verification_summary_off", "App signature not spoofed"), StringResource("revanced_spoof_signature_verification_user_dialog_message", "Turning off this setting may cause playback issues.") diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt deleted file mode 100644 index 44be49f99..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.hdrbrightness.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class HDRBrightnessCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt index 787203464..0bdca1b8a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.integrations.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class IntegrationsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt new file mode 100644 index 000000000..395fd022b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/EmbeddedPlayerControlsOverlayFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.misc.integrations.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint +import org.jf.dexlib2.AccessFlags + +object EmbeddedPlayerControlsOverlayFingerprint : IntegrationsFingerprint( + accessFlags = AccessFlags.PRIVATE or AccessFlags.CONSTRUCTOR, + returnType = "V", + parameters = listOf("L", "L", "L"), + customFingerprint = { methodDef, _ -> + methodDef.definingClass.startsWith("Lcom/google/android/apps/youtube/embeddedplayer/service/ui/overlays/controlsoverlay/remoteloaded/") + }, + contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt index 813aaf573..dd5868d78 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt @@ -3,6 +3,6 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint object ServiceFingerprint : IntegrationsFingerprint( - customFingerprint = { methodDef -> methodDef.definingClass.endsWith("ApiPlayerService;") && methodDef.name == "<init>" }, + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("ApiPlayerService;") && methodDef.name == "<init>" }, contextRegisterResolver = { it.implementation!!.registerCount - it.parameters.size } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt index 6fb114baf..10a9dc93d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.patch.annotations.RequiresIntegrations import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility import app.revanced.patches.youtube.misc.integrations.fingerprints.InitFingerprint +import app.revanced.patches.youtube.misc.integrations.fingerprints.EmbeddedPlayerControlsOverlayFingerprint import app.revanced.patches.youtube.misc.integrations.fingerprints.ServiceFingerprint import app.revanced.patches.youtube.misc.integrations.fingerprints.StandalonePlayerFingerprint @@ -13,5 +14,5 @@ import app.revanced.patches.youtube.misc.integrations.fingerprints.StandalonePla @RequiresIntegrations class IntegrationsPatch : AbstractIntegrationsPatch( "Lapp/revanced/integrations/utils/ReVancedUtils;", - listOf(InitFingerprint, StandalonePlayerFingerprint, ServiceFingerprint), + listOf(InitFingerprint, StandalonePlayerFingerprint, ServiceFingerprint, EmbeddedPlayerControlsOverlayFingerprint), ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt index 91a2724c6..9485b3efc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/annotations/OpenLinksExternallyCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.links.open.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class OpenLinksExternallyCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt index f7b41a242..b1d108279 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/BindSessionServiceFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object BindSessionServiceFingerprint : MethodFingerprint( returnType = "L", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf( Opcode.IPUT_OBJECT, Opcode.NEW_INSTANCE, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt index ffacf0355..78b795566 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/GetCustomTabPackageNameFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object GetCustomTabPackageNameFingerprint : MethodFingerprint( returnType = "L", - access = AccessFlags.PUBLIC or AccessFlags.STATIC, + accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( Opcode.CHECK_CAST, Opcode.NEW_INSTANCE, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt index 0901efbbd..b9f80a60b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/fingerprints/InitializeCustomTabSupportFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object InitializeCustomTabSupportFingerprint : MethodFingerprint( returnType = "V", - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, opcodes = listOf( Opcode.CHECK_CAST, Opcode.NEW_INSTANCE, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt index ec2e2b5fa..64750c53c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/links/open/patch/OpenLinksExternallyPatch.kt @@ -34,11 +34,10 @@ class OpenLinksExternallyPatch : BytecodePatch( override fun execute(context: BytecodeContext): PatchResult { SettingsPatch.PreferenceScreen.MISC.addPreferences( SwitchPreference( - "revanced_enable_external_browser", - StringResource("revanced_enable_external_browser_title", "Open links in browser"), - true, - StringResource("revanced_enable_external_browser_summary_on", "Opening links externally"), - StringResource("revanced_enable_external_browser_summary_off", "Opening links in app") + "revanced_external_browser", + StringResource("revanced_external_browser_title", "Open links in browser"), + StringResource("revanced_external_browser_summary_on", "Opening links externally"), + StringResource("revanced_external_browser_summary_off", "Opening links in app") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt index 6a55da3b2..7d483d276 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt @@ -3,23 +3,7 @@ package app.revanced.patches.youtube.misc.litho.filter.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class LithoFilterCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferFingerprint.kt new file mode 100644 index 000000000..9e0997936 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ProtobufBufferFingerprint.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.misc.litho.filter.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object ProtobufBufferFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.IGET_OBJECT, // References the field required below. + null, + null, + null, + null, + null, + null, + null, + null, + null, + null, + Opcode.IF_NEZ, + Opcode.CONST_4, + Opcode.GOTO, + Opcode.CHECK_CAST, // Casts the referenced field to a specific type that stores the protobuf buffer. + Opcode.INVOKE_VIRTUAL + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt index f5174c190..84c53504c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt @@ -17,6 +17,7 @@ import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.litho.filter.annotation.LithoFilterCompatibility import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ComponentContextParserFingerprint import app.revanced.patches.youtube.misc.litho.filter.fingerprints.EmptyComponentBuilderFingerprint +import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ProtobufBufferFingerprint import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ReadComponentIdentifierFingerprint import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @@ -32,7 +33,9 @@ class LithoFilterPatch : BytecodePatch( ) { override fun execute(context: BytecodeContext): PatchResult { ComponentContextParserFingerprint.result?.also { - arrayOf(EmptyComponentBuilderFingerprint, ReadComponentIdentifierFingerprint).forEach { fingerprint -> + arrayOf( + EmptyComponentBuilderFingerprint, ReadComponentIdentifierFingerprint, ProtobufBufferFingerprint + ).forEach { fingerprint -> if (!fingerprint.resolve(context, it.mutableMethod, it.mutableClass)) return fingerprint.toErrorResult() } @@ -45,26 +48,54 @@ class LithoFilterPatch : BytecodePatch( val builderMethodDescriptor = instruction(builderMethodIndex).descriptor val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).descriptor // Register is overwritten right after it is used in this patch, therefore free to clobber. - val clobberedRegister = instruction(insertHookIndex - 1).twoRegisterA + val free = instruction<TwoRegisterInstruction>(insertHookIndex - 1).registerA + val free2 = instruction<OneRegisterInstruction>(insertHookIndex).registerA @Suppress("UnnecessaryVariable") // The register, this patch clobbers, is previously used for the StringBuilder, // later on a new StringBuilder is instantiated on it. - val stringBuilderRegister = clobberedRegister + val stringBuilderRegister = free - val identifierRegister = instruction(ReadComponentIdentifierFingerprint.patternScanEndIndex).oneRegisterA + val identifierRegister = + instruction<OneRegisterInstruction>(ReadComponentIdentifierFingerprint.patternScanEndIndex).registerA + + // Parameter that holds a ref to a type with a field that ref the protobuf buffer object. + val protobufParameterNumber = 3 + + // Get the field that stores an protobuf buffer required below. + val protobufBufferRefTypeRefFieldDescriptor = + instruction(ProtobufBufferFingerprint.patternScanStartIndex).descriptor + val protobufBufferRefTypeDescriptor = + instruction(ProtobufBufferFingerprint.patternScanEndIndex - 1).descriptor + val protobufBufferFieldDescriptor = "$protobufBufferRefTypeDescriptor->b:Ljava/nio/ByteBuffer;" addInstructions( - insertHookIndex, // right after setting the component.pathBuilder field, + insertHookIndex, // right after setting the component.pathBuilder field. """ - invoke-static {v$stringBuilderRegister, v$identifierRegister}, Lapp/revanced/integrations/patches/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z - move-result v$clobberedRegister - if-eqz v$clobberedRegister, :not_an_ad - move-object/from16 v$clobberedRegister, p1 - invoke-static {v$clobberedRegister}, $builderMethodDescriptor - move-result-object v$clobberedRegister - iget-object v$clobberedRegister, v$clobberedRegister, $emptyComponentFieldDescriptor - return-object v$clobberedRegister + # Get the protobuf buffer object. + + move-object/from16 v$free2, p$protobufParameterNumber + iget-object v$free2, v$free2, $protobufBufferRefTypeRefFieldDescriptor + check-cast v$free2, $protobufBufferRefTypeDescriptor + + # Register "free" now holds the protobuf buffer object + + iget-object v$free2, v$free2, $protobufBufferFieldDescriptor + + # Invoke the filter method. + + invoke-static { v$stringBuilderRegister, v$identifierRegister, v$free2 }, $FILTER_METHOD_DESCRIPTOR + move-result v$free + + if-eqz v$free, :not_an_ad + + # If the filter method returned true, then return a replacement empty component. + + move-object/from16 v$free, p1 + invoke-static {v$free}, $builderMethodDescriptor + move-result-object v$free + iget-object v$free, v$free, $emptyComponentFieldDescriptor + return-object v$free """, listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex))) ) @@ -75,16 +106,20 @@ class LithoFilterPatch : BytecodePatch( } private companion object { + private val MethodFingerprint.patternScanResult + get() = result!!.scanResult.patternScanResult!! + val MethodFingerprint.patternScanEndIndex - get() = result!!.scanResult.patternScanResult!!.endIndex + get() = patternScanResult.endIndex + + val MethodFingerprint.patternScanStartIndex + get() = patternScanResult.startIndex val Instruction.descriptor get() = (this as ReferenceInstruction).reference.toString() - val Instruction.oneRegisterA - get() = (this as OneRegisterInstruction).registerA - - val Instruction.twoRegisterA - get() = (this as TwoRegisterInstruction).registerA + const val FILTER_METHOD_DESCRIPTOR = + "Lapp/revanced/integrations/patches/components/LithoFilterPatch;" + + "->filter(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/nio/ByteBuffer;)Z" } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt index 101098dba..352ed3746 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.microg.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class MicroGPatchCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt index 9a5926896..68bb5e91b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt @@ -10,9 +10,8 @@ import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patches.shared.fingerprints.WatchWhileActivityFingerprint -import app.revanced.patches.shared.misc.fix.spoof.patch.ClientSpoofPatch import app.revanced.patches.youtube.layout.buttons.cast.patch.HideCastButtonPatch -import app.revanced.patches.youtube.misc.fix.playback.patch.SpoofSignatureVerificationPatch +import app.revanced.patches.youtube.misc.fix.playback.patch.ClientSpoofPatch import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility import app.revanced.patches.youtube.misc.microg.fingerprints.* import app.revanced.patches.youtube.misc.microg.patch.resource.MicroGResourcePatch @@ -25,6 +24,7 @@ import app.revanced.util.microg.MicroGBytecodeHelper [ MicroGResourcePatch::class, HideCastButtonPatch::class, + ClientSpoofPatch::class ] ) @Name("vanced-microg-support") diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt index 257f779e2..51e6d5827 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt @@ -32,8 +32,8 @@ class MicroGResourcePatch : ResourcePatch { SettingsPatch.addPreference( Preference( StringResource("microg_settings", "MicroG Settings"), - Preference.Intent("$MICROG_VENDOR.android.gms", "", "org.microg.gms.ui.SettingsActivity"), StringResource("microg_settings_summary", "Settings for MicroG"), + Preference.Intent("$MICROG_VENDOR.android.gms", "", "org.microg.gms.ui.SettingsActivity") ) ) SettingsPatch.renameIntentsTargetPackage(REVANCED_PACKAGE_NAME) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt index 6a59fbcc1..88bff32b0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.minimizedplayback.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class MinimizedPlaybackCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/KidsMinimizedPlaybackPolicyControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/KidsMinimizedPlaybackPolicyControllerFingerprint.kt index 9a9f629bd..9763d18d3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/KidsMinimizedPlaybackPolicyControllerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/KidsMinimizedPlaybackPolicyControllerFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint( returnType = "V", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("I", "L", "L"), opcodes = listOf( Opcode.IF_EQZ, @@ -19,5 +19,7 @@ object KidsMinimizedPlaybackPolicyControllerFingerprint : MethodFingerprint( Opcode.IGET, Opcode.INVOKE_STATIC ), - customFingerprint = { it.definingClass.endsWith("MinimizedPlaybackPolicyController;") } + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("MinimizedPlaybackPolicyController;") + } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt index ee2ad6f25..ba8d9be8d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt @@ -44,7 +44,7 @@ class MinimizedPlaybackPatch : BytecodePatch( SettingsPatch.PreferenceScreen.MISC.addPreferences( NonInteractivePreference( StringResource("revanced_minimized_playback_enabled_title", "Minimized playback"), - StringResource("revanced_minimized_playback_summary_on", "This setting can be found in Settings -> General") + StringResource("revanced_minimized_playback_summary_on", "This setting can be found in Settings -> Background") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt index 15b40d0ea..296b6477b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.playercontrols.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class PlayerControlsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt index 9df6bcf0c..902f88943 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt @@ -12,7 +12,7 @@ object BottomControlsInflateFingerprint : MethodFingerprint( Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT_OBJECT ), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && (instruction as? WideLiteralInstruction)?.wideLiteral == PlayerControlsBytecodePatch.bottomUiContainerResourceId diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt index 91e0acb01..0bf59e705 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt @@ -6,7 +6,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PlayerControlsVisibilityFingerprint : MethodFingerprint( "V", parameters = listOf("Z", "Z"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("YouTubeControlsOverlay;") } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt index ca85a8986..89a6fa3d4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.playeroverlay.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class PlayerOverlaysHookCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt index 1defdfe65..1317e14dc 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt @@ -4,7 +4,7 @@ package app.revanced.patches.youtube.misc.playeroverlay.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && methodDef.name == "onFinishInflate" } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt index 4a3244cdd..dff4ca516 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt @@ -3,22 +3,6 @@ package app.revanced.patches.youtube.misc.playertype.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class PlayerTypeHookCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/PlayerTypeFingerprint.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/PlayerTypeFingerprint.kt index 0eb8e9a11..c6588b82f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/PlayerTypeFingerprint.kt @@ -1,15 +1,14 @@ package app.revanced.patches.youtube.misc.playertype.fingerprint import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -@FuzzyPatternScanMethod(2) -object UpdatePlayerTypeFingerprint : MethodFingerprint( - "V", - AccessFlags.PUBLIC or AccessFlags.FINAL, +object PlayerTypeFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), opcodes = listOf( Opcode.INVOKE_VIRTUAL, Opcode.IGET_OBJECT, @@ -29,5 +28,8 @@ object UpdatePlayerTypeFingerprint : MethodFingerprint( Opcode.INVOKE_STATIC, Opcode.INVOKE_VIRTUAL, Opcode.RETURN_VOID - ) + ), + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("YouTubePlayerOverlaysLayout;") + } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt new file mode 100644 index 000000000..259915bca --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/VideoStateFingerprint.kt @@ -0,0 +1,24 @@ +package app.revanced.patches.youtube.misc.playertype.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VideoStateFingerprint : MethodFingerprint( + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + returnType = "V", + parameters = listOf("L"), + opcodes = listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.CONST_4, + Opcode.IF_EQZ, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, // obfuscated parameter field name + ), + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("YouTubeControlsOverlay;") + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt index 75e722072..999356376 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt @@ -1,34 +1,61 @@ package app.revanced.patches.youtube.misc.playertype.patch +import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.playertype.annotation.PlayerTypeHookCompatibility -import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint +import app.revanced.patches.youtube.misc.playertype.fingerprint.PlayerTypeFingerprint +import app.revanced.patches.youtube.misc.playertype.fingerprint.VideoStateFingerprint +import org.jf.dexlib2.iface.instruction.ReferenceInstruction @Name("player-type-hook") -@Description("Hook to get the current player type of WatchWhileActivity") +@Description("Hook to get the current player type and video playback state.") @PlayerTypeHookCompatibility @Version("0.0.1") @DependsOn([IntegrationsPatch::class]) class PlayerTypeHookPatch : BytecodePatch( - listOf( - UpdatePlayerTypeFingerprint - ) + listOf(PlayerTypeFingerprint, VideoStateFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - // hook YouTubePlayerOverlaysLayout.updatePlayerLayout() - UpdatePlayerTypeFingerprint.result!!.mutableMethod.addInstruction( - 0, - "invoke-static { p1 }, Lapp/revanced/integrations/patches/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V" - ) + + PlayerTypeFingerprint.result?.let { + it.mutableMethod.apply { + addInstruction( + 0, + "invoke-static {p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->setPlayerType(Ljava/lang/Enum;)V" + ) + } + } ?: return PlayerTypeFingerprint.toErrorResult() + + VideoStateFingerprint.result?.let { + it.mutableMethod.apply { + val endIndex = it.scanResult.patternScanResult!!.endIndex + val videoStateFieldName = instruction<ReferenceInstruction>(endIndex).reference + addInstructions( + 0, """ + iget-object v0, p1, $videoStateFieldName # copy VideoState parameter field + invoke-static {v0}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoState(Ljava/lang/Enum;)V + """ + ) + } + } ?: return VideoStateFingerprint.toErrorResult() + return PatchResultSuccess() } + + companion object { + private const val INTEGRATIONS_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/patches/PlayerTypeHookPatch;" + } + } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt index 11395105f..42a9f0afa 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt @@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object LicenseActivityFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.definingClass.endsWith("LicenseActivity;") && methodDef.name == "onCreate" } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/SetThemeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/SetThemeFingerprint.kt new file mode 100644 index 000000000..468e8e244 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/SetThemeFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object SetThemeFingerprint : MethodFingerprint( + returnType = "L", + opcodes = listOf(Opcode.RETURN_OBJECT), + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { instruction -> + if (instruction.opcode != Opcode.CONST) return@any false + + val wideLiteral = (instruction as WideLiteralInstruction).wideLiteral + + SettingsResourcePatch.appearanceStringId == wideLiteral + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt deleted file mode 100644 index 1fceecd38..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt +++ /dev/null @@ -1,25 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object ThemeSetterAppFingerprint : MethodFingerprint( - "L", - AccessFlags.PUBLIC or AccessFlags.STATIC, - parameters = listOf("L", "L", "L", "L"), - opcodes = listOf( - Opcode.CONST, // target reference - Opcode.GOTO, - Opcode.CONST, // target reference - Opcode.INVOKE_DIRECT, - Opcode.RETURN_OBJECT, - Opcode.NEW_INSTANCE, - null, // changed from invoke interface to invoke virtual - Opcode.MOVE_RESULT_OBJECT, - Opcode.SGET_OBJECT, - Opcode.IF_NE, - Opcode.CONST, // target reference - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt deleted file mode 100644 index d57892735..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object ThemeSetterSystemFingerprint : MethodFingerprint( - "L", - opcodes = listOf(Opcode.RETURN_OBJECT), - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { - it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == SettingsResourcePatch.appearanceStringId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt index 331389068..8804f02c5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt @@ -7,6 +7,8 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess @@ -15,78 +17,61 @@ import app.revanced.patches.shared.settings.preference.impl.Preference import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterAppFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint +import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.SetThemeFingerprint import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.util.MethodUtil -@DependsOn( - [ - IntegrationsPatch::class, - SettingsResourcePatch::class, - ] -) +@DependsOn([IntegrationsPatch::class, SettingsResourcePatch::class, ]) @Name("settings") @Description("Adds settings for ReVanced to YouTube.") @Version("0.0.1") class SettingsPatch : BytecodePatch( - listOf(LicenseActivityFingerprint, ThemeSetterSystemFingerprint, ThemeSetterAppFingerprint) + listOf(LicenseActivityFingerprint, SetThemeFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - fun buildInvokeInstructionsString( + // TODO: Remove this when it is only required at one place. + fun getSetThemeInstructionString( registers: String = "v0", classDescriptor: String = THEME_HELPER_DESCRIPTOR, methodName: String = SET_THEME_METHOD_NAME, parameters: String = "Ljava/lang/Object;" - ) = "invoke-static {$registers}, $classDescriptor->$methodName($parameters)V" + ) = "invoke-static { $registers }, $classDescriptor->$methodName($parameters)V" - // apply the current theme of the settings page - ThemeSetterSystemFingerprint.result!!.let { result -> - val call = buildInvokeInstructionsString() - result.mutableMethod.apply { - addInstruction( - result.scanResult.patternScanResult!!.startIndex, call - ) - addInstructions( - implementation!!.instructions.size - 1, call - ) - } - } + SetThemeFingerprint.result?.mutableMethod?.let { setThemeMethod -> + setThemeMethod.implementation!!.instructions.mapIndexedNotNull { i, instruction -> + if (instruction.opcode == Opcode.RETURN_OBJECT) i else null + } + .asReversed() // Prevent index shifting. + .forEach { returnIndex -> + // The following strategy is to replace the return instruction with the setTheme instruction, + // then add a return instruction after the setTheme instruction. + // This is done because the return instruction is a target of another instruction. - // set the theme based on the preference of the app - ThemeSetterAppFingerprint.result?.apply { - fun buildInstructionsString(theme: Int) = """ - const/4 v0, 0x$theme - ${buildInvokeInstructionsString(parameters = "I")} - """ + setThemeMethod.apply { + // This register is returned by the setTheme method. + val register = instruction<OneRegisterInstruction>(returnIndex).registerA - val patternScanResult = scanResult.patternScanResult!! + val setThemeInstruction = getSetThemeInstructionString("v$register") + replaceInstruction(returnIndex, setThemeInstruction) + addInstruction(returnIndex + 1, "return-object v0") + } + } + } ?: return SetThemeFingerprint.toErrorResult() - mutableMethod.apply { - addInstructions( - patternScanResult.endIndex + 1, buildInstructionsString(1) - ) - addInstructions( - patternScanResult.endIndex - 7, buildInstructionsString(0) - ) - addInstructions( - patternScanResult.endIndex - 9, buildInstructionsString(1) - ) - addInstructions( - implementation!!.instructions.size - 2, buildInstructionsString(0) - ) - } - } ?: return ThemeSetterAppFingerprint.toErrorResult() - // set the theme based on the preference of the device + // Modify the license activity and remove all existing layout code. + // Must modify an existing activity and cannot add a new activity to the manifest, + // as that fails for root installations. LicenseActivityFingerprint.result!!.apply licenseActivity@{ mutableMethod.apply { fun buildSettingsActivityInvokeString( registers: String = "p0", classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR, methodName: String = "initializeSettings", - parameters: String = this@licenseActivity.mutableClass.type - ) = buildInvokeInstructionsString(registers, classDescriptor, methodName, parameters) + parameters: String = "Landroid/app/Activity;" + ) = getSetThemeInstructionString(registers, classDescriptor, methodName, parameters) // initialize the settings addInstructions( @@ -95,9 +80,6 @@ class SettingsPatch : BytecodePatch( return-void """ ) - - // set the current theme - addInstruction(0, buildSettingsActivityInvokeString(methodName = "setTheme")) } // remove method overrides @@ -106,14 +88,13 @@ class SettingsPatch : BytecodePatch( } } + return PatchResultSuccess() } internal companion object { private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations" - private const val SETTINGS_ACTIVITY_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settingsmenu/ReVancedSettingActivity;" - private const val THEME_HELPER_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/utils/ThemeHelper;" private const val SET_THEME_METHOD_NAME = "setTheme" @@ -128,6 +109,15 @@ class SettingsPatch : BytecodePatch( fun renameIntentsTargetPackage(newPackage: String) { SettingsResourcePatch.overrideIntentsTargetPackage = newPackage } + + /** + * Creates an intent to open ReVanced settings of the given name + */ + fun createReVancedSettingsIntent(settingsName: String) = Preference.Intent( + "com.google.android.youtube", + settingsName, + "com.google.android.libraries.social.licenses.LicenseActivity" + ) } /** @@ -137,6 +127,7 @@ class SettingsPatch : BytecodePatch( val ADS = Screen("ads", "Ads", "Ad related settings") val INTERACTIONS = Screen("interactions", "Interaction", "Settings related to interactions") val LAYOUT = Screen("layout", "Layout", "Settings related to the layout") + val VIDEO = Screen("video", "Video", "Settings related to the video player") val MISC = Screen("misc", "Misc", "Miscellaneous patches") override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) { diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt index 4248b6778..86665f511 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt @@ -10,15 +10,13 @@ import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch import app.revanced.patches.shared.settings.preference.addPreference -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.* import app.revanced.patches.shared.settings.resource.patch.AbstractSettingsResourcePatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.util.resources.ResourceUtils import app.revanced.util.resources.ResourceUtils.copyResources import app.revanced.util.resources.ResourceUtils.mergeStrings +import org.w3c.dom.Element import org.w3c.dom.Node @Name("settings-resource-patch") @@ -32,49 +30,66 @@ class SettingsResourcePatch : AbstractSettingsResourcePatch( override fun execute(context: ResourceContext): PatchResult { super.execute(context) - /* - * used by a fingerprint of SettingsPatch - */ + // Used for a fingerprint from SettingsPatch. appearanceStringId = ResourceMappingPatch.resourceMappings.find { it.type == "string" && it.name == "app_theme_appearance_dark" }!!.id - /* - * create missing directory for the resources - */ - context["res/drawable-ldrtl-xxxhdpi"].mkdirs() - /* * copy layout resources */ arrayOf( - ResourceUtils.ResourceGroup( - "layout", - "revanced_settings_toolbar.xml", - "revanced_settings_with_toolbar.xml", - "revanced_settings_with_toolbar_layout.xml" - ), ResourceUtils.ResourceGroup( - // required resource for back button, because when the base APK is used, this resource will not exist - "drawable-xxxhdpi", "quantum_ic_arrow_back_white_24.png" - ), ResourceUtils.ResourceGroup( - // required resource for back button, because when the base APK is used, this resource will not exist - "drawable-ldrtl-xxxhdpi", "quantum_ic_arrow_back_white_24.png" - ) + ResourceUtils.ResourceGroup("layout", "revanced_settings_with_toolbar.xml") ).forEach { resourceGroup -> context.copyResources("settings", resourceGroup) } preferencesEditor = context.xmlEditor["res/xml/settings_fragment.xml"] + // Modify the manifest and add an data intent filter to the LicenseActivity. + // Some devices freak out if undeclared data is passed to an intent, + // and this change appears to fix the issue. + context.xmlEditor["AndroidManifest.xml"].use { editor -> + // An xml regular expression would probably work better than this manual searching. + val manifestNodes = editor.file.getElementsByTagName("manifest").item(0).childNodes + for (i in 0..manifestNodes.length) { + val node = manifestNodes.item(i) + if (node != null && node.nodeName == "application") { + val applicationNodes = node.childNodes + for (j in 0..applicationNodes.length) { + val applicationChild = applicationNodes.item(j) + if (applicationChild is Element && applicationChild.nodeName == "activity" + && applicationChild.getAttribute("android:name") == "com.google.android.libraries.social.licenses.LicenseActivity" + ) { + val intentFilter = editor.file.createElement("intent-filter") + val mimeType = editor.file.createElement("data") + mimeType.setAttribute("android:mimeType", "text/plain") + intentFilter.appendChild(mimeType) + applicationChild.appendChild(intentFilter) + break + } + } + } + } + } + + // Add the ReVanced settings to the YouTube settings - val youtubePackage = "com.google.android.youtube" SettingsPatch.addPreference( Preference( StringResource("revanced_settings", "ReVanced"), - Preference.Intent( - youtubePackage, "revanced_settings", "com.google.android.libraries.social.licenses.LicenseActivity" - ), StringResource("revanced_settings_summary", "ReVanced specific settings"), + SettingsPatch.createReVancedSettingsIntent("revanced_settings") + ) + ) + + SettingsPatch.PreferenceScreen.MISC.addPreferences( + TextPreference( + key = null, + title = StringResource("revanced_pref_import_export_title", "Import / Export"), + summary = StringResource("revanced_pref_import_export_summary", "Import / Export ReVanced settings"), + inputType = InputType.TEXT_MULTI_LINE, + tag = "app.revanced.integrations.settingsmenu.ImportExportPreference" ) ) @@ -85,11 +100,8 @@ class SettingsResourcePatch : AbstractSettingsResourcePatch( internal companion object { - // Used by a fingerprint of SettingsPatch - // this field is located in the SettingsResourcePatch - // because if it were to be defined in the SettingsPatch companion object, - // the companion object could be initialized before ResourceMappingResourcePatch has executed. - internal var appearanceStringId: Long = -1 + // Used for a fingerprint from SettingsPatch. + internal var appearanceStringId = -1L // if this is not null, all intents will be renamed to this var overrideIntentsTargetPackage: String? = null diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt deleted file mode 100644 index eae4e1c02..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class CustomPlaybackSpeedCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt deleted file mode 100644 index 541601fd1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object VideoSpeedPatchFingerprint : MethodFingerprint( - opcodes = listOf(Opcode.FILL_ARRAY_DATA), - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("CustomVideoSpeedPatch;") && methodDef.name == "<clinit>" - } -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt deleted file mode 100644 index c038ba497..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt +++ /dev/null @@ -1,195 +0,0 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.patch.* -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.speed.custom.annotations.CustomPlaybackSpeedCompatibility -import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint -import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedLimiterFingerprint -import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.VideoSpeedPatchFingerprint -import org.jf.dexlib2.builder.instruction.BuilderArrayPayload -import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.FieldReference -import org.jf.dexlib2.iface.reference.MethodReference -import java.util.stream.DoubleStream -import kotlin.math.roundToInt - -@Patch -@Name("custom-video-speed") -@Description("Adds more video speed options.") -@DependsOn([IntegrationsPatch::class]) -@CustomPlaybackSpeedCompatibility -@Version("0.0.1") -class CustomVideoSpeedPatch : BytecodePatch( - listOf( - SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint, VideoSpeedPatchFingerprint - ) -) { - - override fun execute(context: BytecodeContext): PatchResult { - val speedLimitMin = minVideoSpeed!!.toFloat() - val speedLimitMax = maxVideoSpeed!!.toFloat().coerceAtLeast(speedLimitMin) - val speedsGranularity = videoSpeedsGranularity!!.toFloat() - - val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!! - val arrayGenMethodImpl = arrayGenMethod.implementation!! - - val sizeCallIndex = arrayGenMethodImpl.instructions - .indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" } - - if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()") - - val sizeCallResultRegister = - (arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA - - arrayGenMethod.replaceInstruction( - sizeCallIndex + 1, - "const/4 v$sizeCallResultRegister, 0x0" - ) - - val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex() - .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 } - - val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA - - val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->videoSpeeds:[F" - - arrayGenMethod.addInstructions( - arrayLengthConstIndex + 1, - """ - sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType - array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination - """ - ) - - val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex() - .first { - val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference) - reference?.definingClass?.contains("PlayerConfigModel") ?: false && - reference?.type == "[F" - } - - val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA - - arrayGenMethod.replaceInstruction( - originalArrayFetchIndex, - "sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType" - ) - - val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!! - val limiterMethodImpl = limiterMethod.implementation!! - - val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex() - .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } - val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex() - .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() } - - val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA - val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA - - fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits()) - - limiterMethod.replaceInstruction( - limiterMinConstIndex, - "const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}" - ) - limiterMethod.replaceInstruction( - limiterMaxConstIndex, - "const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}" - ) - - val constructorResult = VideoSpeedPatchFingerprint.result!! - val constructor = constructorResult.mutableMethod - val implementation = constructor.implementation!! - - val stepsGranularity = 8F - val step = speedLimitMax - .minus(speedLimitMin) // calculate the range of the speeds - .div(speedsGranularity) - .times(stepsGranularity) - .roundToInt() - .div(stepsGranularity)// round to nearest multiple of stepsGranularity - .coerceAtLeast(1 / stepsGranularity) // ensure steps are at least 1/8th of the step granularity - - val videoSpeedsArray = buildList<Number> { - DoubleStream - .iterate(speedLimitMin.toDouble()) { it + step } // create a stream of speeds - .let { speedStream -> - for (speed in speedStream) { - if (speed > speedLimitMax) break - add(speed.toFloat().toRawBits()) - } - } - } - - // adjust the new array of speeds size - constructor.replaceInstruction( - 0, - "const/16 v0, ${videoSpeedsArray.size}" - ) - - // create the payload with the new speeds - val arrayPayloadIndex = implementation.instructions.size - 1 - implementation.replaceInstruction( - arrayPayloadIndex, - BuilderArrayPayload( - 4, - videoSpeedsArray - ) - ) - - return PatchResultSuccess() - } - - companion object : OptionsContainer() { - private fun String?.validate(max: Int? = null) = this?.toFloatOrNull() != null && - toFloat().let { float -> - float > 0 && max?.let { max -> float <= max } ?: true - } - - val videoSpeedsGranularity by option( - PatchOption.StringOption( - "granularity", - "16", - "Video speed granularity", - "The granularity of the video speeds. The higher the value, the more speeds will be available.", - true - ) { - it.validate() - } - ) - - val minVideoSpeed by option( - PatchOption.StringOption( - "min", - "0.25", - "Minimum video speed", - "The minimum video speed.", - true - ) { - it.validate() - } - ) - - val maxVideoSpeed by option( - PatchOption.StringOption( - "max", - "5.0", - "Maximum video speed", - "The maximum video speed. Must be greater than the minimum video speed and smaller than 5.", - true - ) { - it.validate(5) - } - ) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt deleted file mode 100644 index 9fb318f77..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/annotation/RememberPlaybackSpeedCompatibility.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.youtube.misc.video.speed.remember.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package("com.google.android.youtube", arrayOf("18.08.37", "18.15.40", "18.16.37"))] -) -@Target(AnnotationTarget.CLASS) -internal annotation class RememberPlaybackSpeedCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt deleted file mode 100644 index 63111f104..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.youtube.misc.video.videoid.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) -@Target(AnnotationTarget.CLASS) -internal annotation class VideoIdCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt index 37d47fee1..628499d60 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt @@ -4,22 +4,6 @@ import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package // TODO: delete this -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf( - "17.49.37", - "18.03.36", - "18.03.42", - "18.04.35", - "18.04.41", - "18.05.32", - "18.05.35", - "18.05.40", - "18.08.37", - "18.15.40", - "18.16.37" - ) - )] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class CustomVideoBufferCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt index 89cccda3c..a3e5eedfe 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt @@ -12,9 +12,9 @@ import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.shared.settings.preference.impl.StringResource import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.youtube.misc.zoomhaptics.annotations.ZoomHapticsCompatibility import app.revanced.patches.youtube.misc.zoomhaptics.fingerprints.ZoomHapticsFingerprint @@ -32,7 +32,6 @@ class ZoomHapticsPatch : BytecodePatch( SwitchPreference( "revanced_disable_zoom_haptics", StringResource("revanced_disable_zoom_haptics_title", "Disable zoom haptics"), - true, StringResource("revanced_disable_zoom_haptics_summary_on", "Haptics are disabled"), StringResource("revanced_disable_zoom_haptics_summary_off", "Haptics are enabled") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt new file mode 100644 index 000000000..29e7da076 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/annotations/HDRBrightnessCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.video.hdrbrightness.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class HDRBrightnessCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt index 979f4e8a5..0db80f880 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.hdrbrightness.fingerprints +package app.revanced.patches.youtube.video.hdrbrightness.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/patch/HDRBrightnessPatch.kt similarity index 76% rename from src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/patch/HDRBrightnessPatch.kt index f84efbee9..6b8ae5b01 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/hdrbrightness/patch/HDRBrightnessPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.hdrbrightness.patch +package app.revanced.patches.youtube.video.hdrbrightness.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -10,8 +10,8 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.hdrbrightness.annotations.HDRBrightnessCompatibility -import app.revanced.patches.youtube.misc.hdrbrightness.fingerprints.HDRBrightnessFingerprint +import app.revanced.patches.youtube.video.hdrbrightness.annotations.HDRBrightnessCompatibility +import app.revanced.patches.youtube.video.hdrbrightness.fingerprints.HDRBrightnessFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch import app.revanced.patches.shared.settings.preference.impl.StringResource @@ -30,13 +30,12 @@ class HDRBrightnessPatch : BytecodePatch( listOf(HDRBrightnessFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( SwitchPreference( - "revanced_pref_hdr_autobrightness", - StringResource("revanced_hdr_autobrightness_enabled_title", "Enable auto HDR brightness"), - true, - StringResource("revanced_hdr_autobrightness_summary_on", "Auto HDR brightness is enabled"), - StringResource("revanced_hdr_autobrightness_summary_off", "Auto HDR brightness is disabled") + "revanced_hdr_auto_brightness", + StringResource("revanced_hdr_auto_brightness_title", "Enable auto HDR brightness"), + StringResource("revanced_hdr_auto_brightness_summary_on", "Auto HDR brightness is enabled"), + StringResource("revanced_hdr_auto_brightness_summary_off", "Auto HDR brightness is disabled") ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt similarity index 51% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt index 6e7f87614..2ff6163df 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/annotation/VideoInformationCompatibility.kt @@ -1,10 +1,8 @@ -package app.revanced.patches.youtube.misc.video.information.annotation +package app.revanced.patches.youtube.video.information.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package("com.google.android.youtube", arrayOf("18.08.37", "18.15.40", "18.16.37"))] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class VideoInformationCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt index 13f82a926..5bfa9579d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt similarity index 68% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt index 648f1a7e3..edb712070 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/OnPlaybackSpeedItemClickFingerprint.kt @@ -1,10 +1,10 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode object OnPlaybackSpeedItemClickFingerprint : MethodFingerprint( - customFingerprint = { it.name == "onItemClick" }, + customFingerprint = { methodDef, _ -> methodDef.name == "onItemClick" }, opcodes = listOf( Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt similarity index 81% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt index fe0355d68..628421a01 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerInitFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerInitFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerInitFingerprint.kt index 7e6485525..d772935b5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerInitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/PlayerInitFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/SeekFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekFingerprint.kt similarity index 70% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/SeekFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekFingerprint.kt index 8f2ba9663..c6d9b2879 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/SeekFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/SeekFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoLengthFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoLengthFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoLengthFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoLengthFingerprint.kt index 2d9e98682..89d4d16c6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoLengthFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoLengthFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoTimeFingerprint.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoTimeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoTimeFingerprint.kt index d04b75377..c09c69ab9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoTimeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/fingerprints/VideoTimeFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints +package app.revanced.patches.youtube.video.information.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/information/patch/VideoInformationPatch.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/information/patch/VideoInformationPatch.kt index 77f44a9ed..1df612641 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/information/patch/VideoInformationPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.patch +package app.revanced.patches.youtube.video.information.patch import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description @@ -19,16 +19,15 @@ import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility -import app.revanced.patches.youtube.misc.video.information.fingerprints.* -import app.revanced.patches.youtube.misc.video.speed.remember.patch.RememberPlaybackSpeedPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch +import app.revanced.patches.youtube.video.information.annotation.VideoInformationCompatibility +import app.revanced.patches.youtube.video.information.fingerprints.* +import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackSpeedPatch +import app.revanced.patches.youtube.video.videoid.patch.VideoIdPatch import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction -import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.immutable.ImmutableMethod @@ -54,7 +53,7 @@ class VideoInformationPatch : BytecodePatch( playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) } // hook the player controller for use through integrations - onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "playerController_onCreateHook") + onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "initialize") // seek method val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method @@ -93,7 +92,7 @@ class VideoInformationPatch : BytecodePatch( with(videoLengthMethodResult.mutableMethod) { val videoLengthRegisterIndex = videoLengthMethodResult.scanResult.patternScanResult!!.endIndex - 2 - val videoLengthRegister = (instruction(videoLengthRegisterIndex) as OneRegisterInstruction).registerA + val videoLengthRegister = instruction<OneRegisterInstruction>(videoLengthRegisterIndex).registerA val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide addInstruction( @@ -140,7 +139,7 @@ class VideoInformationPatch : BytecodePatch( speedSelectionInsertMethod = mutableMethod speedSelectionInsertIndex = scanResult.patternScanResult!!.startIndex - 3 speedSelectionValueRegister = - (mutableMethod.instruction(speedSelectionInsertIndex) as FiveRegisterInstruction).registerD + mutableMethod.instruction<FiveRegisterInstruction>(speedSelectionInsertIndex).registerD val speedSelectionMethodInstructions = mutableMethod.implementation!!.instructions setPlaybackSpeedContainerClassFieldReference = @@ -160,24 +159,32 @@ class VideoInformationPatch : BytecodePatch( private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/VideoInformation;" private lateinit var playerInitMethod: MutableMethod + private var playerInitInsertIndex = 4 + private lateinit var timeMethod: MutableMethod + private var timeInitInsertIndex = 2 + private lateinit var highPrecisionTimeMethod: MutableMethod + private var highPrecisionInsertIndex = 0 - private fun MutableMethod.insert(insert: InsertIndex, register: String, descriptor: String) = - addInstruction(insert.index, "invoke-static { $register }, $descriptor") + private fun MutableMethod.insert(insertIndex: Int, register: String, descriptor: String) = + addInstruction(insertIndex, "invoke-static { $register }, $descriptor") - private fun MutableMethod.insertTimeHook(insert: InsertIndex, descriptor: String) = - insert(insert, "p1, p2", descriptor) + private fun MutableMethod.insertTimeHook(insertIndex: Int, descriptor: String) = + insert(insertIndex, "p1, p2", descriptor) /** - * Hook the player controller. + * Hook the player controller. Called when a video is opened or the current video is changed. + * + * Note: This hook is called very early and is called before the video id, video time, video length, + * and many other data fields are set. * * @param targetMethodClass The descriptor for the class to invoke when the player controller is created. * @param targetMethodName The name of the static method to invoke when the player controller is created. */ internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) = playerInitMethod.insert( - InsertIndex.CREATE, + playerInitInsertIndex++, "v0", "$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" ) @@ -191,7 +198,7 @@ class VideoInformationPatch : BytecodePatch( */ internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) = timeMethod.insertTimeHook( - InsertIndex.TIME, + timeInitInsertIndex++, "$targetMethodClass->$targetMethodName(J)V" ) @@ -205,20 +212,13 @@ class VideoInformationPatch : BytecodePatch( */ internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) = highPrecisionTimeMethod.insertTimeHook( - InsertIndex.HIGH_PRECISION_TIME, + highPrecisionInsertIndex++, "$targetMethodClass->$targetMethodName(J)V" ) - enum class InsertIndex(internal val index: Int) { - CREATE(4), - TIME(2), - HIGH_PRECISION_TIME(0), - } - private fun getReference(instructions: List<BuilderInstruction>, offset: Int, opcode: Opcode) = - instructions[instructions.indexOfFirst { it.opcode == opcode } + offset].reference - - val Instruction.reference get() = (this as ReferenceInstruction).reference.toString() + (instructions[instructions.indexOfFirst { it.opcode == opcode } + offset] as ReferenceInstruction) + .reference.toString() private lateinit var speedSelectionInsertMethod: MutableMethod private var speedSelectionInsertIndex = 0 diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt new file mode 100644 index 000000000..701f9974d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.video.oldqualitylayout.annotations + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class OldQualityLayoutCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt new file mode 100644 index 000000000..bce667560 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt @@ -0,0 +1,34 @@ +package app.revanced.patches.youtube.video.oldqualitylayout.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.video.oldqualitylayout.patch.OldQualityLayoutResourcePatch +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object QualityMenuViewInflateFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.INVOKE_SUPER, + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_16, + Opcode.INVOKE_VIRTUAL, + Opcode.CONST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST + ), + customFingerprint = { methodDef, _ -> + methodDef.implementation?.instructions?.any { + if (it.opcode != Opcode.CONST) return@any false + + val literal = (it as WideLiteralInstruction).wideLiteral + + literal == OldQualityLayoutResourcePatch.videoQualityBottomSheetListFragmentTitle + } ?: false + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutPatch.kt similarity index 55% rename from src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutPatch.kt index dd4597b01..1dcdf0303 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.oldqualitylayout.patch +package app.revanced.patches.youtube.video.oldqualitylayout.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -10,36 +10,19 @@ import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility -import app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.video.oldqualitylayout.annotations.OldQualityLayoutCompatibility +import app.revanced.patches.youtube.video.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction @Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) +@DependsOn([IntegrationsPatch::class, OldQualityLayoutResourcePatch::class]) @Name("old-quality-layout") -@Description("Enables the original video quality flyout in the video player settings") +@Description("Enables the original video quality flyout in the video player settings.") @OldQualityLayoutCompatibility @Version("0.0.1") -// new ReVanced users have no idea what it means to use the "old quality layout menu" -// maybe rename this patch to better describe what it provides (ie: user-selectable-video-resolution ) -class OldQualityLayoutPatch : BytecodePatch( - listOf(QualityMenuViewInflateFingerprint) -) { +class OldQualityLayoutPatch : BytecodePatch(listOf(QualityMenuViewInflateFingerprint)) { override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_use_old_style_quality_settings", - StringResource("revanced_old_style_quality_settings_enabled_title", "Use old video quality player menu"), - true, - StringResource("revanced_old_style_quality_settings_summary_on", "Old video quality menu is used"), - StringResource("revanced_old_style_quality_settings_summary_off", "Old video quality menu is not used") - ) - ) - val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!! val method = inflateFingerprintResult.mutableMethod val instructions = method.implementation!!.instructions @@ -58,4 +41,4 @@ class OldQualityLayoutPatch : BytecodePatch( return PatchResultSuccess() } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutResourcePatch.kt new file mode 100644 index 000000000..965486ce5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/oldqualitylayout/patch/OldQualityLayoutResourcePatch.kt @@ -0,0 +1,36 @@ +package app.revanced.patches.youtube.video.oldqualitylayout.patch + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch + +@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) +class OldQualityLayoutResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( + SwitchPreference( + "revanced_show_old_video_menu", + StringResource("revanced_show_old_video_menu_title", "Use old video quality player menu"), + StringResource("revanced_show_old_video_menu_summary_on", "Old video quality menu is used"), + StringResource("revanced_show_old_video_menu_summary_off", "Old video quality menu is not used") + ) + ) + + videoQualityBottomSheetListFragmentTitle = + ResourceMappingPatch.resourceMappings.find { it.name == "video_quality_bottom_sheet_list_fragment_title" } + ?.id ?: return PatchResultError("Could not find resource") + + return PatchResultSuccess() + } + + internal companion object { + var videoQualityBottomSheetListFragmentTitle = -1L + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt similarity index 52% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt index 7e871ff60..789e422eb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/annotations/RememberVideoQualityCompatibility.kt @@ -1,10 +1,8 @@ -package app.revanced.patches.youtube.misc.video.quality.annotations +package app.revanced.patches.youtube.video.quality.annotations import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility( - [Package("com.google.android.youtube", arrayOf("18.08.37", "18.15.40", "18.16.37"))] -) +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) @Target(AnnotationTarget.CLASS) internal annotation class RememberVideoQualityCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt index 896b5de3e..d69bb8406 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/SetQualityByIndexMethodClassFieldReferenceFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.quality.fingerprints +package app.revanced.patches.youtube.video.quality.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt similarity index 76% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt index 592c62fc0..a9e590671 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualityItemOnClickParentFingerprint.kt @@ -1,5 +1,5 @@ -package app.revanced.patches.youtube.misc.video.quality.fingerprints +package app.revanced.patches.youtube.video.quality.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySetterFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySetterFingerprint.kt index 9a29d162b..ab95b0b5b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/fingerprints/VideoQualitySetterFingerprint.kt @@ -1,5 +1,5 @@ -package app.revanced.patches.youtube.misc.video.quality.fingerprints +package app.revanced.patches.youtube.video.quality.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt similarity index 70% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt index d5a03e33b..635563bf1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/patch/RememberVideoQualityPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.quality.patch +package app.revanced.patches.youtube.video.quality.patch import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description @@ -20,16 +20,16 @@ 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.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.youtube.misc.video.quality.annotations.RememberVideoQualityCompatibility -import app.revanced.patches.youtube.misc.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint -import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint -import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualitySetterFingerprint -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch +import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch +import app.revanced.patches.youtube.video.quality.annotations.RememberVideoQualityCompatibility +import app.revanced.patches.youtube.video.quality.fingerprints.SetQualityByIndexMethodClassFieldReferenceFingerprint +import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualityItemOnClickParentFingerprint +import app.revanced.patches.youtube.video.quality.fingerprints.VideoQualitySetterFingerprint import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.reference.FieldReference @Patch -@DependsOn([IntegrationsPatch::class, VideoIdPatch::class, SettingsPatch::class]) +@DependsOn([IntegrationsPatch::class, VideoInformationPatch::class, SettingsPatch::class]) @Name("remember-video-quality") @Description("Adds the ability to remember the video quality you chose in the video quality flyout.") @RememberVideoQualityCompatibility @@ -41,14 +41,38 @@ class RememberVideoQualityPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( + // This is bloated as each value has it's own String key/value + // ideally the entries would be raw values (and not a key to a String resource) + val entries = listOf( + StringResource("revanced_video_quality_default_entry_1", "Automatic quality"), + StringResource("revanced_video_quality_default_entry_2", "2160p"), + StringResource("revanced_video_quality_default_entry_3", "1440p"), + StringResource("revanced_video_quality_default_entry_4", "1080p"), + StringResource("revanced_video_quality_default_entry_5", "720p"), + StringResource("revanced_video_quality_default_entry_6", "480p"), + StringResource("revanced_video_quality_default_entry_7", "360p"), + StringResource("revanced_video_quality_default_entry_8", "280p"), + StringResource("revanced_video_quality_default_entry_9", "144p"), + ) + val entryValues = listOf( + StringResource("revanced_video_quality_default_entry_value_1", "-2"), + StringResource("revanced_video_quality_default_entry_value_2", "2160"), + StringResource("revanced_video_quality_default_entry_value_3", "1440"), + StringResource("revanced_video_quality_default_entry_value_4", "1080"), + StringResource("revanced_video_quality_default_entry_value_5", "720"), + StringResource("revanced_video_quality_default_entry_value_6", "480"), + StringResource("revanced_video_quality_default_entry_value_7", "360"), + StringResource("revanced_video_quality_default_entry_value_8", "280"), + StringResource("revanced_video_quality_default_entry_value_9", "144"), + ) + + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( SwitchPreference( "revanced_remember_video_quality_last_selected", StringResource( "revanced_remember_video_quality_last_selected_title", "Remember video quality changes" ), - true, StringResource( "revanced_remember_video_quality_last_selected_summary_on", "Quality changes apply to all videos" @@ -57,52 +81,25 @@ class RememberVideoQualityPatch : BytecodePatch( "revanced_remember_video_quality_last_selected_summary_off", "Quality changes only apply to the current video" ) - ) - ) - - // This is bloated as each value has it's own String key/value - // ideally the entries would be raw values (and not a key to a String resource) - val entries = listOf( - StringResource("revanced_default_quality_entry_1", "Automatic quality"), - StringResource("revanced_default_quality_entry_2", "2160p"), - StringResource("revanced_default_quality_entry_3", "1440p"), - StringResource("revanced_default_quality_entry_4", "1080p"), - StringResource("revanced_default_quality_entry_5", "720p"), - StringResource("revanced_default_quality_entry_6", "480p"), - StringResource("revanced_default_quality_entry_7", "360p"), - StringResource("revanced_default_quality_entry_8", "280p"), - StringResource("revanced_default_quality_entry_9", "144p"), - ) - val entryValues = listOf( - StringResource("revanced_default_quality_entry_value_1", "-2"), - StringResource("revanced_default_quality_entry_value_2", "2160"), - StringResource("revanced_default_quality_entry_value_3", "1440"), - StringResource("revanced_default_quality_entry_value_4", "1080"), - StringResource("revanced_default_quality_entry_value_5", "720"), - StringResource("revanced_default_quality_entry_value_6", "480"), - StringResource("revanced_default_quality_entry_value_7", "360"), - StringResource("revanced_default_quality_entry_value_8", "280"), - StringResource("revanced_default_quality_entry_value_9", "144"), - ) - SettingsPatch.PreferenceScreen.MISC.addPreferences( + ), ListPreference( - "revanced_default_video_quality_wifi", + "revanced_video_quality_default_wifi", StringResource( - "revanced_default_video_quality_wifi_title", + "revanced_video_quality_default_wifi_title", "Default video quality on Wi-Fi network" ), - ArrayResource("revanced_video_quality_wifi_entry", entries), - ArrayResource("revanced_video_quality_wifi_entry_values", entryValues) + ArrayResource("revanced_video_quality_default_wifi_entry", entries), + ArrayResource("revanced_video_quality_default_wifi_entry_values", entryValues) // default value and summary are set by integrations after loading ), ListPreference( - "revanced_default_video_quality_mobile", + "revanced_video_quality_default_mobile", StringResource( - "revanced_default_video_quality_mobile_title", + "revanced_video_quality_default_mobile_title", "Default video quality on mobile network" ), - ArrayResource("revanced_video_quality_mobile_entries", entries), - ArrayResource("revanced_video_quality_mobile_entry_values", entryValues) + ArrayResource("revanced_video_quality_default_mobile_entries", entries), + ArrayResource("revanced_video_quality_default_mobile_values", entryValues) ) ) @@ -114,7 +111,7 @@ class RememberVideoQualityPatch : BytecodePatch( * Conveniently, at this point the video quality is overridden to the remembered playback speed. */ - VideoIdPatch.injectCall("$INTEGRATIONS_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted") // Inject a call to set the remembered quality once a video loads. VideoQualitySetterFingerprint.result?.also { diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt new file mode 100644 index 000000000..a079bd0f3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeed.kt @@ -0,0 +1,27 @@ +package app.revanced.patches.youtube.video.speed + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.video.speed.custom.patch.CustomVideoSpeedPatch +import app.revanced.patches.youtube.video.speed.remember.patch.RememberPlaybackSpeedPatch + +@Patch +@Name("video-speed") +@Description("Adds custom video speeds and ability to remember the playback speed you chose in the video playback speed flyout.") +@DependsOn([CustomVideoSpeedPatch::class, RememberPlaybackSpeedPatch::class]) +@VideoSpeedCompatibility +@Version("0.0.1") +class VideoSpeed : BytecodePatch() { + + override fun execute(context: BytecodeContext): PatchResult { + return PatchResultSuccess() // All patches this patch depends on succeed. + } + +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt new file mode 100644 index 000000000..b97e92931 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/VideoSpeedCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.video.speed + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class VideoSpeedCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt index e4e336880..4d624dab2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints +package app.revanced.patches.youtube.video.speed.custom.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt index 4cb98cd4d..30c315de8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints +package app.revanced.patches.youtube.video.speed.custom.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt new file mode 100644 index 000000000..ae5e53d83 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/custom/patch/CustomVideoSpeedPatch.kt @@ -0,0 +1,121 @@ +package app.revanced.patches.youtube.video.speed.custom.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patches.shared.settings.preference.impl.InputType +import app.revanced.patches.shared.settings.preference.impl.StringResource +import app.revanced.patches.shared.settings.preference.impl.TextPreference +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch +import app.revanced.patches.youtube.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint +import app.revanced.patches.youtube.video.speed.custom.fingerprints.SpeedLimiterFingerprint +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference + +@Name("custom-video-speed") +@Description("Adds custom video speed options.") +@DependsOn([IntegrationsPatch::class]) +@Version("0.0.1") +class CustomVideoSpeedPatch : BytecodePatch( + listOf( + SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint + ) +) { + + override fun execute(context: BytecodeContext): PatchResult { + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( + TextPreference( + key = "revanced_custom_playback_speeds", + title = StringResource( + "revanced_custom_playback_speeds_title", + "Custom playback speeds" + ), + inputType = InputType.TEXT_MULTI_LINE, + summary = StringResource( + "revanced_custom_playback_speeds_summary", + "Add or change the video speeds available" + ) + ) + ) + + val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!! + val arrayGenMethodImpl = arrayGenMethod.implementation!! + + val sizeCallIndex = arrayGenMethodImpl.instructions + .indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" } + + if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()") + + val sizeCallResultRegister = + (arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA + + arrayGenMethod.replaceInstruction( + sizeCallIndex + 1, + "const/4 v$sizeCallResultRegister, 0x0" + ) + + val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex() + .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 } + + val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA + + val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->customVideoSpeeds:[F" + + arrayGenMethod.addInstructions( + arrayLengthConstIndex + 1, + """ + sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType + array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination + """ + ) + + val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex() + .first { + val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference) + reference?.definingClass?.contains("PlayerConfigModel") ?: false && + reference?.type == "[F" + } + + val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA + + arrayGenMethod.replaceInstruction( + originalArrayFetchIndex, + "sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType" + ) + + val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!! + val limiterMethodImpl = limiterMethod.implementation!! + + val lowerLimitConst = 0.25f.toRawBits() + val upperLimitConst = 2.0f.toRawBits() + val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex() + .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == lowerLimitConst } + val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex() + .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == upperLimitConst } + + val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA + val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA + + // edit: alternatively this might work by overriding with fixed values such as 0.1x and 10x + limiterMethod.replaceInstruction( + limiterMinConstIndex, + "sget v$limiterMinConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->minVideoSpeed:F" + ) + limiterMethod.replaceInstruction( + limiterMaxConstIndex, + "sget v$limiterMaxConstDestination, Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->maxVideoSpeed:F" + ) + + return PatchResultSuccess() + } + +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt index e244a298e..31ac21e8a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/fingerprint/InitializePlaybackSpeedValuesFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.remember.fingerprint +package app.revanced.patches.youtube.video.speed.remember.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt similarity index 74% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt index 4895e665a..625d773df 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/remember/patch/RememberPlaybackSpeedPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.remember.patch +package app.revanced.patches.youtube.video.speed.remember.patch import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description @@ -7,9 +7,10 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.settings.preference.impl.ArrayResource import app.revanced.patches.shared.settings.preference.impl.ListPreference @@ -17,17 +18,14 @@ 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.patch.IntegrationsPatch import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch.Companion.reference -import app.revanced.patches.youtube.misc.video.speed.remember.annotation.RememberPlaybackSpeedCompatibility -import app.revanced.patches.youtube.misc.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch +import app.revanced.patches.youtube.video.information.patch.VideoInformationPatch +import app.revanced.patches.youtube.video.speed.custom.patch.CustomVideoSpeedPatch +import app.revanced.patches.youtube.video.speed.remember.fingerprint.InitializePlaybackSpeedValuesFingerprint +import org.jf.dexlib2.iface.instruction.ReferenceInstruction -@Patch @Name("remember-playback-speed") @Description("Adds the ability to remember the playback speed you chose in the video playback speed flyout.") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoIdPatch::class, VideoInformationPatch::class]) -@RememberPlaybackSpeedCompatibility +@DependsOn([IntegrationsPatch::class, SettingsPatch::class, VideoInformationPatch::class, CustomVideoSpeedPatch::class]) @Version("0.0.1") class RememberPlaybackSpeedPatch : BytecodePatch( listOf( @@ -35,14 +33,13 @@ class RememberPlaybackSpeedPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( + SettingsPatch.PreferenceScreen.VIDEO.addPreferences( SwitchPreference( "revanced_remember_playback_speed_last_selected", StringResource( "revanced_remember_playback_speed_last_selected_title", "Remember playback speed changes" ), - true, StringResource( "revanced_remember_playback_speed_last_selected_summary_on", "Playback speed changes apply to all videos" @@ -51,32 +48,28 @@ class RememberPlaybackSpeedPatch : BytecodePatch( "revanced_remember_playback_speed_last_selected_summary_off", "Playback speed changes only apply to the current video" ) - ) - ) - - SettingsPatch.PreferenceScreen.MISC.addPreferences( + ), ListPreference( - "revanced_default_playback_speed", + "revanced_playback_speed_default", StringResource( - "revanced_default_playback_speed_title", + "revanced_playback_speed_default_title", "Default playback speed" ), // Dummy data: // Entries and values are set by Integrations code based on the actual speeds available, // and the values set here are ignored and do nothing. ArrayResource( - "revanced_default_playback_speed_entries", - listOf(StringResource("revanced_default_playback_speed_entry", "1.0x")) + "revanced_playback_speed_default_entries", + listOf(StringResource("revanced_playback_speed_default_entries", "1.0x")) ), ArrayResource( - "revanced_default_playback_speed_entry_values", - listOf(StringResource("revanced_default_playback_speed_entry_value", "1.0")) + "revanced_playback_speed_default_entry_values", + listOf(StringResource("revanced_playback_speed_default_entry_value", "1.0")) ) ) ) - VideoIdPatch.injectCall("${INTEGRATIONS_CLASS_DESCRIPTOR}->newVideoLoaded(Ljava/lang/String;)V") - + VideoInformationPatch.onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "newVideoStarted") VideoInformationPatch.userSelectedPlaybackSpeedHook( INTEGRATIONS_CLASS_DESCRIPTOR, "userSelectedPlaybackSpeed") @@ -85,7 +78,8 @@ class RememberPlaybackSpeedPatch : BytecodePatch( */ InitializePlaybackSpeedValuesFingerprint.result?.apply { // Infer everything necessary for calling the method setPlaybackSpeed(). - val onItemClickListenerClassFieldReference = mutableMethod.instruction(0).reference + val onItemClickListenerClassFieldReference = + mutableMethod.instruction<ReferenceInstruction>(0).reference // Registers are not used at index 0, so they can be freely used. mutableMethod.addInstructions( @@ -122,4 +116,4 @@ class RememberPlaybackSpeedPatch : BytecodePatch( const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/playback/speed/RememberPlaybackSpeedPatch;" } -} \ No newline at end of file +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt new file mode 100644 index 000000000..660f7d8ad --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/annotation/VideoIdCompatibility.kt @@ -0,0 +1,8 @@ +package app.revanced.patches.youtube.video.videoid.annotation + +import app.revanced.patcher.annotation.Compatibility +import app.revanced.patcher.annotation.Package + +@Compatibility([Package("com.google.android.youtube", arrayOf("18.16.37", "18.19.35"))]) +@Target(AnnotationTarget.CLASS) +internal annotation class VideoIdCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt index bed9e90d3..d9c51ab7c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.videoid.fingerprint +package app.revanced.patches.youtube.video.videoid.fingerprint import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -9,7 +9,7 @@ import org.jf.dexlib2.Opcode @FuzzyPatternScanMethod(2) object VideoIdFingerprint : MethodFingerprint( returnType = "V", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L"), opcodes = listOf( Opcode.IF_EQZ, @@ -26,6 +26,7 @@ object VideoIdFingerprint : MethodFingerprint( Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT ), - null, - { it.definingClass.endsWith("SubtitlesOverlayPresenter;") } + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("SubtitlesOverlayPresenter;") + } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt similarity index 56% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt index 44c14a2c2..6f7da47b4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/fingerprint/VideoIdFingerprintBackgroundPlay.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.videoid.fingerprint +package app.revanced.patches.youtube.video.videoid.fingerprint import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint @@ -7,10 +7,10 @@ import org.jf.dexlib2.Opcode object VideoIdFingerprintBackgroundPlay : MethodFingerprint( returnType = "V", - access = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, + accessFlags = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, parameters = listOf("L"), opcodes = listOf(Opcode.INVOKE_INTERFACE), - customFingerprint = { - it.definingClass.endsWith("PlaybackLifecycleMonitor;") + customFingerprint = { methodDef, _ -> + methodDef.definingClass.endsWith("PlaybackLifecycleMonitor;") } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/patch/VideoIdPatch.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/videoid/patch/VideoIdPatch.kt index bf961de7b..4b8fbcc47 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/videoid/patch/VideoIdPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.videoid.patch +package app.revanced.patches.youtube.video.videoid.patch import app.revanced.extensions.toErrorResult import app.revanced.patcher.annotation.Description @@ -13,9 +13,9 @@ import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.videoid.annotation.VideoIdCompatibility -import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprint -import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay +import app.revanced.patches.youtube.video.videoid.annotation.VideoIdCompatibility +import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprint +import app.revanced.patches.youtube.video.videoid.fingerprint.VideoIdFingerprintBackgroundPlay import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Name("video-id-hook") @@ -33,7 +33,7 @@ class VideoIdPatch : BytecodePatch( result.mutableMethod.also { insertMethod = it }.apply { - videoIdRegister = (instruction(videoIdRegisterInstructionIndex) as OneRegisterInstruction).registerA + videoIdRegister = instruction<OneRegisterInstruction>(videoIdRegisterInstructionIndex).registerA insertIndex = videoIdRegisterInstructionIndex + 1 } } ?: return VideoIdFingerprint.toErrorResult() @@ -44,7 +44,7 @@ class VideoIdPatch : BytecodePatch( result.mutableMethod.also { backgroundPlaybackMethod = it }.apply { - backgroundPlaybackVideoIdRegister = (instruction(endIndex + 1) as OneRegisterInstruction).registerA + backgroundPlaybackVideoIdRegister = instruction<OneRegisterInstruction>(endIndex + 1).registerA backgroundPlaybackInsertIndex = endIndex + 2 } } ?: return VideoIdFingerprintBackgroundPlay.toErrorResult() diff --git a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/fingerprints/ContainsAdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/fingerprints/ContainsAdFingerprint.kt index ed26fa039..0b0c1a9b5 100644 --- a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/fingerprints/ContainsAdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/fingerprints/ContainsAdFingerprint.kt @@ -8,7 +8,7 @@ import org.jf.dexlib2.Opcode object ContainsAdFingerprint:MethodFingerprint( returnType = "Z", parameters = listOf("L", "L"), - access = AccessFlags.STATIC or AccessFlags.PUBLIC, + accessFlags = AccessFlags.STATIC or AccessFlags.PUBLIC, opcodes = listOf( Opcode.CONST_STRING, Opcode.INVOKE_INTERFACE, @@ -18,7 +18,7 @@ object ContainsAdFingerprint:MethodFingerprint( Opcode.INVOKE_INTERFACE ), strings = listOf("ads_video_with_context"), - customFingerprint = { methodDef -> + customFingerprint = { methodDef, _ -> methodDef.name == "containsAd" && methodDef.definingClass.endsWith("LithoAdRemoval;") } ) { diff --git a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt index 09fd98117..e704e983d 100644 --- a/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtubevanced/ad/general/patch/HideAdsPatch.kt @@ -32,7 +32,7 @@ class HideAdsPatch : BytecodePatch( ContainsAdFingerprint.result?.let { result -> result.mutableMethod.apply { val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1 - val adsListRegister = (instruction(insertIndex - 2) as Instruction21c).registerA + val adsListRegister = instruction<Instruction21c>(insertIndex - 2).registerA listOf( "_buttoned_layout", diff --git a/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/IsPremiumFingerprint.kt b/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/IsPremiumFingerprint.kt index 0a7f01a25..4835c4048 100644 --- a/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/IsPremiumFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/IsPremiumFingerprint.kt @@ -7,7 +7,7 @@ import org.jf.dexlib2.Opcode object IsPremiumFingerprint : MethodFingerprint( returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf( Opcode.IGET_BOOLEAN, Opcode.RETURN, diff --git a/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/YukaUserConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/YukaUserConstructorFingerprint.kt index 85351e471..67aba3720 100644 --- a/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/YukaUserConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/yuka/misc/unlockpremium/fingerprints/YukaUserConstructorFingerprint.kt @@ -6,7 +6,7 @@ import org.jf.dexlib2.AccessFlags object YukaUserConstructorFingerprint : MethodFingerprint( returnType = "V", - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, strings = listOf( "premiumProvider" ) diff --git a/src/main/kotlin/app/revanced/util/patch/BytecodeUtils.kt b/src/main/kotlin/app/revanced/util/patch/BytecodeUtils.kt new file mode 100644 index 000000000..d62857323 --- /dev/null +++ b/src/main/kotlin/app/revanced/util/patch/BytecodeUtils.kt @@ -0,0 +1,16 @@ +package app.revanced.util.patch + +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +/** + * @return the first constant instruction with the resource id, or -1 if not found. + */ +fun Method.indexOfFirstConstantInstruction(constantValue: Long): Int { + return implementation?.let { + it.instructions.indexOfFirst { instruction -> + instruction.opcode == Opcode.CONST && (instruction as WideLiteralInstruction).wideLiteral == constantValue + } + } ?: -1 +} \ No newline at end of file diff --git a/src/main/resources/copyvideourl/host/values/strings.xml b/src/main/resources/copyvideourl/host/values/strings.xml new file mode 100644 index 000000000..8452816c3 --- /dev/null +++ b/src/main/resources/copyvideourl/host/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <string name="revanced_share_copy_url_success">URL copied to clipboard</string> + <string name="revanced_share_copy_url_timestamp_success">URL with timestamp copied</string> +</resources> diff --git a/src/main/resources/returnyoutubedislike/host/values/strings.xml b/src/main/resources/returnyoutubedislike/host/values/strings.xml index 31ca93597..e887fe5ce 100644 --- a/src/main/resources/returnyoutubedislike/host/values/strings.xml +++ b/src/main/resources/returnyoutubedislike/host/values/strings.xml @@ -13,6 +13,10 @@ <string name="revanced_ryd_enable_summary_on">Dislikes are shown</string> <string name="revanced_ryd_enable_summary_off">Dislikes are not shown</string> + <string name="revanced_ryd_shorts_title">Show dislikes on Shorts</string> + <string name="revanced_ryd_shorts_summary_on">Dislikes shown on Shorts</string> + <string name="revanced_ryd_shorts_summary_off">Dislikes hidden on Shorts</string> + <string name="revanced_ryd_dislike_percentage_title">Dislikes as percentage</string> <string name="revanced_ryd_dislike_percentage_summary_on">Dislikes shown as percentage</string> <string name="revanced_ryd_dislike_percentage_summary_off">Dislikes shown as number</string> @@ -21,9 +25,13 @@ <string name="revanced_ryd_compact_layout_summary_on">Like button styled for minimum width</string> <string name="revanced_ryd_compact_layout_summary_off">Like button styled for best appearance</string> + <string name="ryd_toast_on_connection_error_title">Show toast if API not available</string> + <string name="ryd_toast_on_connection_error_summary_on">Toast shown if ReturnYouTubeDislike API is not available</string> + <string name="ryd_toast_on_connection_error_summary_off">Toast not shown if ReturnYouTubeDislike API is not available</string> + <string name="revanced_ryd_about">About</string> <string name="revanced_ryd_attribution_title">ReturnYouTubeDislike.com</string> - <string name="revanced_ryd_attribution_summary">Dislike data is provided by the Return YouTube Dislike API. Tap here to learn more.</string> + <string name="revanced_ryd_attribution_summary">Data is provided by the Return YouTube Dislike API. Tap here to learn more.</string> <string name="revanced_ryd_statistics_category_title">ReturnYouTubeDislike API statistics of this device</string> diff --git a/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png b/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png deleted file mode 100644 index d409b544b..000000000 Binary files a/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png and /dev/null differ diff --git a/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png b/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png deleted file mode 100644 index e27034d67..000000000 Binary files a/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png and /dev/null differ diff --git a/src/main/resources/settings/host/values/strings.xml b/src/main/resources/settings/host/values/strings.xml index c0740672f..75802473c 100644 --- a/src/main/resources/settings/host/values/strings.xml +++ b/src/main/resources/settings/host/values/strings.xml @@ -1,4 +1,12 @@ <?xml version="1.0" encoding="utf-8"?> <resources> + <string name="revanced_settings_title">ReVanced</string> <string name="revanced_settings_confirm_user_dialog_title">Do you wish to proceed?</string> + <string name="revanced_settings_reset">Reset</string> + + <string name="revanced_settings_import">Import</string> + <string name="revanced_settings_import_copy">Copy</string> + <string name="revanced_settings_import_reset">ReVanced settings reset to default</string> + <string name="revanced_settings_import_success">Imported %d settings</string> + <string name="revanced_settings_import_failure_parse">Import failed: %s</string> </resources> diff --git a/src/main/resources/settings/layout/revanced_settings_toolbar.xml b/src/main/resources/settings/layout/revanced_settings_toolbar.xml deleted file mode 100644 index 86c717712..000000000 --- a/src/main/resources/settings/layout/revanced_settings_toolbar.xml +++ /dev/null @@ -1,4 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@color/yt_white1" android:layout_width="match_parent" android:layout_height="wrap_content" android:elevation="4dp"> - <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:background="?attr/ytBrandBackgroundSolid" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:navigationIcon="@drawable/quantum_ic_arrow_back_white_24" app:title="@string/revanced_settings"/> -</FrameLayout> \ No newline at end of file diff --git a/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml b/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml index 21ff59780..150088114 100644 --- a/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml +++ b/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml @@ -1,4 +1,33 @@ <?xml version="1.0" encoding="utf-8"?> -<merge> - <include layout="@layout/revanced_settings_with_toolbar_layout"/> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="match_parent" + android:fitsSystemWindows="true" + android:orientation="vertical" + android:transitionGroup="true"> + + <FrameLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:background="@color/yt_white1" + android:elevation="4dp"> + + <android.support.v7.widget.Toolbar + android:id="@+id/revanced_toolbar" + android:layout_width="match_parent" + android:layout_height="?attr/actionBarSize" + android:background="?attr/ytBrandBackgroundSolid" + app:navigationIcon="@drawable/yt_outline_arrow_left_black_24" + app:title="@string/revanced_settings" /> + </FrameLayout> + + <FrameLayout + android:id="@+id/revanced_settings_fragments" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + + </LinearLayout> </merge> \ No newline at end of file diff --git a/src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml b/src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml deleted file mode 100644 index 31b20d945..000000000 --- a/src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:fitsSystemWindows="true" android:layout_width="match_parent" android:layout_height="match_parent" android:transitionGroup="true"> - <include layout="@layout/revanced_settings_toolbar"/> - <FrameLayout android:id="@+id/revanced_settings_fragments" android:layout_width="match_parent" android:layout_height="match_parent"/> -</LinearLayout> \ No newline at end of file diff --git a/src/main/resources/sponsorblock/host/values/strings.xml b/src/main/resources/sponsorblock/host/values/strings.xml index c8f014afc..d451ce290 100644 --- a/src/main/resources/sponsorblock/host/values/strings.xml +++ b/src/main/resources/sponsorblock/host/values/strings.xml @@ -35,6 +35,9 @@ <string name="sb_guidelines_popup_open">Show me</string> <string name="sb_general">General</string> + <string name="sb_toast_on_connection_error_title">Show toast if API is not available</string> + <string name="sb_toast_on_connection_error_summary_on">Toast shown if SponsorBlock API is not available</string> + <string name="sb_toast_on_connection_error_summary_off">Toast not shown if SponsorBlock API is not available</string> <string name="sb_general_skipcount">Enable skip count tracking</string> <string name="sb_general_skipcount_sum_on">Lets the SponsorBlock leaderboard know how much time is saved. A message is sent to the leaderboard each time a segment is skipped</string> <string name="sb_general_skipcount_sum_off">Skip count tracking is not enabled</string> @@ -42,17 +45,21 @@ <string name="sb_general_min_duration_sum">Segments shorter than this value (in seconds) will not be shown or skipped</string> <string name="sb_general_uuid">Your private user id</string> <string name="sb_general_uuid_sum">This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you</string> - <string name="sb_general_uuid_invalid">User id cannot be blank</string> + <string name="sb_general_uuid_invalid">Private user id must be at least 30 characters long</string> <string name="sb_general_api_url">Change API URL</string> <string name="sb_general_api_url_sum">The address SponsorBlock uses to make calls to the server. Do not change this unless you know what you\'re doing</string> <string name="sb_api_url_reset">API URL reset</string> <string name="sb_api_url_invalid">API URL is invalid</string> <string name="sb_api_url_changed">API URL changed</string> <string name="sb_settings_ie">Import/Export settings</string> + <string name="sb_settings_copy">Copy</string> <string name="sb_settings_ie_sum">Your SponsorBlock JSON configuration that can be imported/exported to ReVanced and other SponsorBlock platforms. This includes your private user id. Be sure to share this wisely</string> <string name="sb_settings_import_successful">Settings imported successfully</string> <string name="sb_settings_import_failed">Failed to import: %s</string> - <string name="sb_settings_export_failed">Failed to export settings (try clearing app data)</string> + <string name="sb_settings_export_failed">Failed to export: %s</string> + + <string name="sb_settings_revanced_export_user_id_warning">Your settings contain a private SponsorBlock user id.\n\nYour user id is like a password and it should never be shared.\n</string> + <string name="sb_settings_revanced_export_user_id_warning_dismiss">Do not show again</string> <string name="sb_diff_segments">Change segment behavior</string> <string name="sb_segments_sponsor">Sponsor</string> @@ -113,10 +120,10 @@ <string name="sb_skip_seekbaronly">Show in seek bar</string> <string name="sb_skip_ignore">Disable</string> - <string name="sb_submit_failed_invalid" formatted="false">Can\'t submit the segment: %s</string> - <string name="sb_submit_failed_timeout">Unable to submit segments (API timed out)</string> - <string name="sb_submit_failed_unknown_error" formatted="false">Unable to submit segments (status: %d %s)</string> - <string name="sb_submit_failed_rate_limit">Can\'t submit the segment.\nRate Limited (too many from the same user or IP)</string> + <string name="sb_submit_failed_invalid" formatted="false">Unable to submit segment: %s</string> + <string name="sb_submit_failed_timeout">SponsorBlock is temporarily down</string> + <string name="sb_submit_failed_unknown_error" formatted="false">Unable to submit segment (status: %d %s)</string> + <string name="sb_submit_failed_rate_limit">Unable to submit segment.\nRate Limited (too many from the same user or IP)</string> <string name="sb_submit_failed_forbidden" formatted="false">Can\'t submit the segment: %s</string> <string name="sb_submit_failed_duplicate">Can\'t submit the segment.\nAlready exists</string> <string name="sb_submit_succeeded">Segment submitted successfully</string> diff --git a/src/main/resources/theme/values-night-v31/styles.xml b/src/main/resources/theme/values-night-v31/styles.xml deleted file mode 100644 index 53da895f8..000000000 --- a/src/main/resources/theme/values-night-v31/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="Base.Theme.YouTube.Launcher" parent="@style/Theme.AppCompat.NoActionBar"> - <item name="android:windowSplashScreenBackground">@android:color/black</item> - <item name="android:windowSplashScreenAnimatedIcon">@drawable/avd_anim</item> - <item name="android:windowSplashScreenAnimationDuration">1000</item> - </style> -</resources>