Compare commits

...

544 Commits

Author SHA1 Message Date
semantic-release-bot
b340769cf3 chore: Release v5.35.0-dev.3 [skip ci]
# [5.35.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.35.0-dev.2...v5.35.0-dev.3) (2025-09-04)

### Bug Fixes

* **Instagram - Hide navigation buttons:** Fix Manager patching error ([0a8cd7a](0a8cd7a7db))
2025-09-04 14:06:03 +00:00
LisoUseInAIKyrios
0a8cd7a7db fix(Instagram - Hide navigation buttons): Fix Manager patching error 2025-09-04 16:01:50 +02:00
semantic-release-bot
39f90e4b11 chore: Release v5.35.0-dev.2 [skip ci]
# [5.35.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.35.0-dev.1...v5.35.0-dev.2) (2025-09-04)

### Bug Fixes

* Revert dependency updates to fix Manager pre-release patching ([9256aa4](9256aa4548))
2025-09-04 10:27:39 +00:00
LisoUseInAIKyrios
9256aa4548 fix: Revert dependency updates to fix Manager pre-release patching 2025-09-04 12:23:56 +02:00
semantic-release-bot
7973c75552 chore: Release v5.35.0-dev.1 [skip ci]
# [5.35.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.34.1-dev.3...v5.35.0-dev.1) (2025-09-03)

### Features

* **Instagram:** Add `Hide navigation buttons` patch ([#5678](https://github.com/ReVanced/revanced-patches/issues/5678)) ([1dbc2d4](1dbc2d4057))
2025-09-03 17:43:47 +00:00
github-actions[bot]
2b2307416a chore: Sync translations (#5755) 2025-09-03 19:41:04 +02:00
PainfulPaladins
1dbc2d4057 feat(Instagram): Add Hide navigation buttons patch (#5678)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-09-03 19:39:25 +02:00
dependabot[bot]
f6917dc361 chore(deps): Bump com.google.protobuf:protoc from 4.31.1 to 4.32.0 (#5751) 2025-09-02 18:28:15 +02:00
dependabot[bot]
d2f043e11a chore(deps): Bump com.google.protobuf:protobuf-javalite from 4.31.1 to 4.32.0 (#5750) 2025-09-02 17:10:45 +02:00
dependabot[bot]
a392bc0dfd chore(deps): Bump actions/setup-java from 4 to 5 (#5746) 2025-09-02 12:43:12 +02:00
dependabot[bot]
dfc127048a chore(deps): Bump actions/attest-build-provenance from 2 to 3 (#5743) 2025-09-02 12:42:08 +02:00
dependabot[bot]
ed31d0cab6 chore(deps): Bump actions/checkout from 4 to 5 (#5745) 2025-09-02 12:41:29 +02:00
dependabot[bot]
0df6315f9c chore(deps): Bump cycjimmy/semantic-release-action from 4 to 5 (#5741) 2025-09-02 12:40:08 +02:00
semantic-release-bot
f14259f9ef chore: Release v5.34.1-dev.3 [skip ci]
## [5.34.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.34.1-dev.2...v5.34.1-dev.3) (2025-08-24)

### Bug Fixes

* **YouTube - Hide layout components:** Hide Playable shelf header ([1473db0](1473db0bef))
2025-08-24 03:30:00 +00:00
LisoUseInAIKyrios
1473db0bef fix(YouTube - Hide layout components): Hide Playable shelf header 2025-08-23 23:26:02 -04:00
github-actions[bot]
829ca58a55 chore: Sync translations (#5707) 2025-08-23 23:23:49 -04:00
semantic-release-bot
aace741e25 chore: Release v5.34.1-dev.2 [skip ci]
## [5.34.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.34.1-dev.1...v5.34.1-dev.2) (2025-08-22)

### Bug Fixes

* **Proton mail:** Constrain patches to last working app target ([1895291](189529151a))
2025-08-22 04:12:59 +00:00
LisoUseInAIKyrios
189529151a fix(Proton mail): Constrain patches to last working app target 2025-08-22 00:10:03 -04:00
semantic-release-bot
51237c177a chore: Release v5.34.1-dev.1 [skip ci]
## [5.34.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.34.0...v5.34.1-dev.1) (2025-08-21)

### Bug Fixes

* **Spotify - Unlock Premium:** Make compatible with latest versions again by fixing fingerprint ([#5684](https://github.com/ReVanced/revanced-patches/issues/5684)) ([23496c7](23496c7c36))
2025-08-21 19:20:39 +00:00
Nuckyz
23496c7c36 fix(Spotify - Unlock Premium): Make compatible with latest versions again by fixing fingerprint (#5684) 2025-08-21 15:17:29 -04:00
semantic-release-bot
e6823d8924 chore: Release v5.34.0 [skip ci]
# [5.34.0](https://github.com/ReVanced/revanced-patches/compare/v5.33.0...v5.34.0) (2025-08-19)

### Bug Fixes

* **Backdrops:** Remove broken patch that is no longer supported ([#5627](https://github.com/ReVanced/revanced-patches/issues/5627)) ([c3e571e](c3e571e765))
* **pixiv - Hide ads:** Constrain patch to last working app target ([b702dce](b702dceda0))
* **Twitch:** Constrain patches to last working app targets ([#5373](https://github.com/ReVanced/revanced-patches/issues/5373)) ([d7eb6e8](d7eb6e87a5))
* **YouTube - Hide layout components:** Do not hide community posts on channel profiles ([#5634](https://github.com/ReVanced/revanced-patches/issues/5634)) ([61824ad](61824ade23))
* **YouTube - Player Controls:** Fix chapter title overlapping the bottom buttons ([#5673](https://github.com/ReVanced/revanced-patches/issues/5673)) ([150bee2](150bee2833))
* **YouTube - SponsorBlock:** Do not hide voting or create button when the video ends ([25470ba](25470baeee))
* **YouTube - Video playback:** Disable HDR video does not disable Dolby Vision HDR ([#5661](https://github.com/ReVanced/revanced-patches/issues/5661)) ([4aaa7ca](4aaa7ca895))
* **YouTube - Video quality:** Fix additional incorrect quality resolutions used by YouTube ([6bd9e49](6bd9e49c7a))
* **YouTube - Video quality:** Show FHD+ icon for 1080p 60fps enhanced bitrate ([e579c56](e579c56921))
* **YouTube:** Use correct fade out animation when tapping to dismiss the video overlay ([#5670](https://github.com/ReVanced/revanced-patches/issues/5670)) ([01a04c3](01a04c338c))

### Features

* **Instagram:** Support latest app version ([#5611](https://github.com/ReVanced/revanced-patches/issues/5611)) ([562e005](562e005772))
* **NU.nl:** Support latest app version ([#5643](https://github.com/ReVanced/revanced-patches/issues/5643)) ([1bb8c53](1bb8c53ed3))
* **YouTube - Hide player flyout menu items:** Add option to hide quality flyout menu ([809e013](809e013c4e))
* **YouTube - Hide video action buttons:** Add "Hide Hype button" setting ([fe66bae](fe66baedb7))
* **YouTube - Hide video action buttons:** Add "Hide Promote button" setting ([40ac8e1](40ac8e1142))
* **YouTube - Playback speed:** Show current playback speed on player speed dialog button ([#5607](https://github.com/ReVanced/revanced-patches/issues/5607)) ([30176a3](30176a3318))
* **YouTube:** Add `Disable sign in to TV popup` patch ([#5639](https://github.com/ReVanced/revanced-patches/issues/5639)) ([56fbd8c](56fbd8cce0))
2025-08-19 15:12:22 +00:00
LisoUseInAIKyrios
43597dab21 chore: Merge branch dev to main (#5617) 2025-08-19 11:08:46 -04:00
semantic-release-bot
c0824db142 chore: Release v5.34.0-dev.13 [skip ci]
# [5.34.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.12...v5.34.0-dev.13) (2025-08-19)

### Bug Fixes

* **YouTube - Player Controls:** Fix chapter title overlapping the bottom buttons ([#5673](https://github.com/ReVanced/revanced-patches/issues/5673)) ([150bee2](150bee2833))
2025-08-19 14:55:36 +00:00
github-actions[bot]
1b7f84b7fa chore: Sync translations (#5677) 2025-08-19 10:52:35 -04:00
semantic-release-bot
6d87c848d6 chore: Release v5.34.0-dev.13 [skip ci]
# [5.34.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.12...v5.34.0-dev.13) (2025-08-18)

### Bug Fixes

* **YouTube - Player Controls:** Fix chapter title overlapping the bottom buttons ([#5673](https://github.com/ReVanced/revanced-patches/issues/5673)) ([150bee2](150bee2833))
2025-08-18 22:29:41 +00:00
MarcaD
150bee2833 fix(YouTube - Player Controls): Fix chapter title overlapping the bottom buttons (#5673)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-08-18 18:27:14 -04:00
semantic-release-bot
c3ee6eca44 chore: Release v5.34.0-dev.12 [skip ci]
# [5.34.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.11...v5.34.0-dev.12) (2025-08-18)

### Bug Fixes

* **YouTube:** Use correct fade out animation when tapping to dismiss the video overlay ([#5670](https://github.com/ReVanced/revanced-patches/issues/5670)) ([01a04c3](01a04c338c))
2025-08-18 00:17:30 +00:00
LisoUseInAIKyrios
01a04c338c fix(YouTube): Use correct fade out animation when tapping to dismiss the video overlay (#5670) 2025-08-17 20:14:44 -04:00
github-actions[bot]
3130225d9d chore: Sync translations (#5671) 2025-08-17 20:13:55 -04:00
LisoUseInAIKyrios
16b27fb872 chore: Fix typo 2025-08-17 11:17:54 -04:00
LisoUseInAIKyrios
bedabd3fa3 refactor: Show SB buttons with other overlay buttons when the video has ended 2025-08-16 16:24:24 -04:00
semantic-release-bot
84f3c6f02d chore: Release v5.34.0-dev.11 [skip ci]
# [5.34.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.10...v5.34.0-dev.11) (2025-08-16)

### Bug Fixes

* **YouTube - SponsorBlock:** Do not hide voting or create button when the video ends ([25470ba](25470baeee))
2025-08-16 20:21:35 +00:00
LisoUseInAIKyrios
25470baeee fix(YouTube - SponsorBlock): Do not hide voting or create button when the video ends
This logic is no longer needed, since YouTube no longer hides the overlay buttons when the video ends
2025-08-16 16:17:43 -04:00
semantic-release-bot
b86da73a87 chore: Release v5.34.0-dev.10 [skip ci]
# [5.34.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.9...v5.34.0-dev.10) (2025-08-16)

### Bug Fixes

* **YouTube - Video playback:** Disable HDR video does not disable Dolby Vision HDR ([#5661](https://github.com/ReVanced/revanced-patches/issues/5661)) ([4aaa7ca](4aaa7ca895))

### Features

* **YouTube - Hide video action buttons:** Add "Hide Promote button" setting ([40ac8e1](40ac8e1142))
2025-08-16 19:14:17 +00:00
LisoUseInAIKyrios
4aaa7ca895 fix(YouTube - Video playback): Disable HDR video does not disable Dolby Vision HDR (#5661) 2025-08-16 15:10:31 -04:00
semantic-release-bot
d3f63461e7 chore: Release v5.34.0-dev.10 [skip ci]
# [5.34.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.9...v5.34.0-dev.10) (2025-08-16)

### Features

* **YouTube - Hide video action buttons:** Add "Hide Promote button" setting ([40ac8e1](40ac8e1142))
2025-08-16 17:53:26 +00:00
github-actions[bot]
7a3ace2231 chore: Sync translations (#5664) 2025-08-16 13:50:35 -04:00
semantic-release-bot
c89668a540 chore: Release v5.34.0-dev.10 [skip ci]
# [5.34.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.9...v5.34.0-dev.10) (2025-08-16)

### Features

* **YouTube - Hide video action buttons:** Add "Hide Promote button" setting ([40ac8e1](40ac8e1142))
2025-08-16 17:26:01 +00:00
LisoUseInAIKyrios
40ac8e1142 feat(YouTube - Hide video action buttons): Add "Hide Promote button" setting 2025-08-16 13:21:00 -04:00
github-actions[bot]
26c6420de5 chore: Sync translations (#5663) 2025-08-16 13:20:25 -04:00
github-actions[bot]
bfd3989995 chore: Sync translations (#5662) 2025-08-16 13:15:10 -04:00
LisoUseInAIKyrios
7e812ae1a8 chore: Fix typo 2025-08-16 12:23:09 -04:00
semantic-release-bot
c23a926b07 chore: Release v5.34.0-dev.9 [skip ci]
# [5.34.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.8...v5.34.0-dev.9) (2025-08-16)

### Features

* **YouTube - Hide video action buttons:** Add "Hide Hype button" setting ([fe66bae](fe66baedb7))
2025-08-16 15:48:20 +00:00
LisoUseInAIKyrios
fe66baedb7 feat(YouTube - Hide video action buttons): Add "Hide Hype button" setting 2025-08-16 11:45:36 -04:00
semantic-release-bot
959f23d1e4 chore: Release v5.34.0-dev.8 [skip ci]
# [5.34.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.7...v5.34.0-dev.8) (2025-08-15)

### Features

* **NU.nl:** Support latest app version ([#5643](https://github.com/ReVanced/revanced-patches/issues/5643)) ([1bb8c53](1bb8c53ed3))
* **YouTube:** Add `Disable sign in to TV popup` patch ([#5639](https://github.com/ReVanced/revanced-patches/issues/5639)) ([56fbd8c](56fbd8cce0))
2025-08-15 10:04:52 +00:00
AndnixSH
56fbd8cce0 feat(YouTube): Add Disable sign in to TV popup patch (#5639) 2025-08-15 06:00:55 -04:00
Jasper Abbink
1bb8c53ed3 feat(NU.nl): Support latest app version (#5643) 2025-08-15 06:00:06 -04:00
github-actions[bot]
5fc0631a15 chore: Sync translations (#5652) 2025-08-15 05:59:43 -04:00
semantic-release-bot
bdbe96beba chore: Release v5.34.0-dev.7 [skip ci]
# [5.34.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.6...v5.34.0-dev.7) (2025-08-13)

### Bug Fixes

* **YouTube - Video quality:** Fix additional incorrect quality resolutions used by YouTube ([6bd9e49](6bd9e49c7a))
2025-08-13 19:20:51 +00:00
LisoUseInAIKyrios
6bd9e49c7a fix(YouTube - Video quality): Fix additional incorrect quality resolutions used by YouTube 2025-08-13 15:16:45 -04:00
semantic-release-bot
f904ca6d7e chore: Release v5.34.0-dev.6 [skip ci]
# [5.34.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.5...v5.34.0-dev.6) (2025-08-11)

### Bug Fixes

* **YouTube - Video quality:** Show FHD+ icon for 1080p 60fps enhanced bitrate ([e579c56](e579c56921))
2025-08-11 01:21:07 +00:00
LisoUseInAIKyrios
e579c56921 fix(YouTube - Video quality): Show FHD+ icon for 1080p 60fps enhanced bitrate 2025-08-10 21:17:32 -04:00
github-actions[bot]
83f239065a chore: Sync translations (#5637) 2025-08-10 21:13:31 -04:00
semantic-release-bot
6499318f33 chore: Release v5.34.0-dev.5 [skip ci]
# [5.34.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.4...v5.34.0-dev.5) (2025-08-10)

### Features

* **YouTube - Hide player flyout menu items:** Add option to hide quality flyout menu ([809e013](809e013c4e))
2025-08-10 13:57:25 +00:00
LisoUseInAIKyrios
809e013c4e feat(YouTube - Hide player flyout menu items): Add option to hide quality flyout menu 2025-08-10 09:54:40 -04:00
semantic-release-bot
182829d51c chore: Release v5.34.0-dev.4 [skip ci]
# [5.34.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.3...v5.34.0-dev.4) (2025-08-10)

### Bug Fixes

* **YouTube - Hide layout components:** Do not hide community posts on channel profiles ([#5634](https://github.com/ReVanced/revanced-patches/issues/5634)) ([61824ad](61824ade23))
2025-08-10 13:11:44 +00:00
LisoUseInAIKyrios
61824ade23 fix(YouTube - Hide layout components): Do not hide community posts on channel profiles (#5634) 2025-08-10 09:09:08 -04:00
LisoUseInAIKyrios
ff4308e961 refactor(YouTube Music - Hide category bar): Fix possible crash when patching certain app targets 2025-08-09 11:13:35 -04:00
semantic-release-bot
b5eb13c0a8 chore: Release v5.34.0-dev.3 [skip ci]
# [5.34.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.2...v5.34.0-dev.3) (2025-08-09)

### Bug Fixes

* **pixiv - Hide ads:** Constrain patch to last working app target ([b702dce](b702dceda0))
2025-08-09 15:06:42 +00:00
LisoUseInAIKyrios
b702dceda0 fix(pixiv - Hide ads): Constrain patch to last working app target 2025-08-09 11:04:07 -04:00
semantic-release-bot
d616652058 chore: Release v5.34.0-dev.2 [skip ci]
# [5.34.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.34.0-dev.1...v5.34.0-dev.2) (2025-08-09)

### Bug Fixes

* **Backdrops:** Remove broken patch that is no longer supported ([#5627](https://github.com/ReVanced/revanced-patches/issues/5627)) ([c3e571e](c3e571e765))

### Features

* **YouTube - Playback speed:** Show current playback speed on player speed dialog button ([#5607](https://github.com/ReVanced/revanced-patches/issues/5607)) ([30176a3](30176a3318))
2025-08-09 01:31:11 +00:00
LisoUseInAIKyrios
c3e571e765 fix(Backdrops): Remove broken patch that is no longer supported (#5627) 2025-08-08 21:28:07 -04:00
MarcaD
30176a3318 feat(YouTube - Playback speed): Show current playback speed on player speed dialog button (#5607)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-08-08 21:27:52 -04:00
semantic-release-bot
9c0638d128 chore: Release v5.34.0-dev.1 [skip ci]
# [5.34.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.33.0...v5.34.0-dev.1) (2025-08-08)

### Bug Fixes

* **Twitch:** Constrain patches to last working app targets ([#5373](https://github.com/ReVanced/revanced-patches/issues/5373)) ([d7eb6e8](d7eb6e87a5))

### Features

* **Instagram:** Support latest app version ([#5611](https://github.com/ReVanced/revanced-patches/issues/5611)) ([562e005](562e005772))
2025-08-08 01:55:22 +00:00
LisoUseInAIKyrios
d7eb6e87a5 fix(Twitch): Constrain patches to last working app targets (#5373) 2025-08-07 21:51:52 -04:00
LisoUseInAIKyrios
562e005772 feat(Instagram): Support latest app version (#5611) 2025-08-07 21:51:01 -04:00
github-actions[bot]
f61218de52 chore: Sync translations (#5616) 2025-08-07 21:50:45 -04:00
semantic-release-bot
a19b670e19 chore: Release v5.33.0 [skip ci]
# [5.33.0](https://github.com/ReVanced/revanced-patches/compare/v5.32.0...v5.33.0) (2025-08-05)

### Bug Fixes

* **Messenger - Hide Facebook button:** Support the latest app version ([#5590](https://github.com/ReVanced/revanced-patches/issues/5590)) ([a28891e](a28891e5f3))
* **NFC Tools:** Remove broken patch that is no longer supported ([#5584](https://github.com/ReVanced/revanced-patches/issues/5584)) ([2e177a8](2e177a8839))
* **YouTube - Force original audio:** Disable a/b feature flag that forces localized audio ([#5582](https://github.com/ReVanced/revanced-patches/issues/5582)) ([1dd01cf](1dd01cf54a))
* **YouTube - Litho filter:** Correctly filter identifier of older YouTube targets ([b1d164b](b1d164b446))
* **YouTube - Playback speed:** Use old speed menu for player button if enabled ([a4817df](a4817dfdd0))
* **YouTube - Video quality:** Fix 144p default not always used ([9afa7d2](9afa7d2ac6))
* **YouTube - Video quality:** Fix dialog quality list check mark not always shown ([1bc63e5](1bc63e50a7))
* **YouTube - Video quality:** Fix wrong qualities sometimes shown in player button dialog ([178eed7](178eed7fcd))
* **YouTube - Video quality:** Use 1080p enhanced bitrate for Premium users ([#5565](https://github.com/ReVanced/revanced-patches/issues/5565)) ([1adbd56](1adbd563b2))

### Features

* **ORF ON:** Add `Remove root detection` patch ([#5551](https://github.com/ReVanced/revanced-patches/issues/5551)) ([d92362b](d92362b0d9))
* **YouTube - Playback speed:** Add "Restore old playback speed menu" option ([#5552](https://github.com/ReVanced/revanced-patches/issues/5552)) ([e9e4cf3](e9e4cf39b6))
* **YouTube:** Add player button to change video quality ([#5435](https://github.com/ReVanced/revanced-patches/issues/5435)) ([7bdc328](7bdc32867a))

### Performance Improvements

* **YouTube:** Filter identifier callback only on root component creation ([#5558](https://github.com/ReVanced/revanced-patches/issues/5558)) ([5d08fdd](5d08fdddb8))
2025-08-05 17:57:09 +00:00
LisoUseInAIKyrios
300d816350 chore: Merge branch dev to main (#5553) 2025-08-05 13:53:31 -04:00
github-actions[bot]
63d64a5c87 chore: Sync translations (#5595) 2025-08-05 13:52:06 -04:00
semantic-release-bot
0cfc31c8f7 chore: Release v5.33.0-dev.13 [skip ci]
# [5.33.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.12...v5.33.0-dev.13) (2025-08-05)

### Bug Fixes

* **Messenger - Hide Facebook button:** Support the latest app version ([#5590](https://github.com/ReVanced/revanced-patches/issues/5590)) ([a28891e](a28891e5f3))
2025-08-05 03:23:38 +00:00
Dawid Krajcarz
a28891e5f3 fix(Messenger - Hide Facebook button): Support the latest app version (#5590) 2025-08-04 23:21:10 -04:00
semantic-release-bot
36036b082d chore: Release v5.33.0-dev.12 [skip ci]
# [5.33.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.11...v5.33.0-dev.12) (2025-08-04)

### Bug Fixes

* **YouTube - Video quality:** Fix dialog quality list check mark not always shown ([1bc63e5](1bc63e50a7))
2025-08-04 19:19:31 +00:00
LisoUseInAIKyrios
1bc63e50a7 fix(YouTube - Video quality): Fix dialog quality list check mark not always shown 2025-08-04 15:17:00 -04:00
semantic-release-bot
4b2b5e3029 chore: Release v5.33.0-dev.11 [skip ci]
# [5.33.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.10...v5.33.0-dev.11) (2025-08-04)

### Bug Fixes

* **YouTube - Video quality:** Fix 144p default not always used ([9afa7d2](9afa7d2ac6))
2025-08-04 19:03:03 +00:00
LisoUseInAIKyrios
9afa7d2ac6 fix(YouTube - Video quality): Fix 144p default not always used 2025-08-04 15:00:14 -04:00
semantic-release-bot
1a8146dbc8 chore: Release v5.33.0-dev.10 [skip ci]
# [5.33.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.9...v5.33.0-dev.10) (2025-08-04)

### Bug Fixes

* **YouTube - Video quality:** Fix wrong qualities sometimes shown in player button dialog ([178eed7](178eed7fcd))
2025-08-04 17:23:50 +00:00
LisoUseInAIKyrios
178eed7fcd fix(YouTube - Video quality): Fix wrong qualities sometimes shown in player button dialog 2025-08-04 13:21:02 -04:00
semantic-release-bot
621292644c chore: Release v5.33.0-dev.9 [skip ci]
# [5.33.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.8...v5.33.0-dev.9) (2025-08-04)

### Bug Fixes

* **YouTube - Force original audio:** Disable a/b feature flag that forces localized audio ([#5582](https://github.com/ReVanced/revanced-patches/issues/5582)) ([1dd01cf](1dd01cf54a))
2025-08-04 01:27:12 +00:00
LisoUseInAIKyrios
1dd01cf54a fix(YouTube - Force original audio): Disable a/b feature flag that forces localized audio (#5582) 2025-08-03 21:23:27 -04:00
semantic-release-bot
8c31374c53 chore: Release v5.33.0-dev.8 [skip ci]
# [5.33.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.7...v5.33.0-dev.8) (2025-08-03)

### Bug Fixes

* **NFC Tools:** Remove broken patch that is no longer supported ([#5584](https://github.com/ReVanced/revanced-patches/issues/5584)) ([2e177a8](2e177a8839))
2025-08-03 23:44:42 +00:00
LisoUseInAIKyrios
2e177a8839 fix(NFC Tools): Remove broken patch that is no longer supported (#5584) 2025-08-03 19:41:54 -04:00
github-actions[bot]
cfffd422f8 chore: Sync translations (#5586) 2025-08-03 19:41:07 -04:00
github-actions[bot]
37aab8382e chore: Sync translations (#5585) 2025-08-03 19:38:17 -04:00
semantic-release-bot
f4950ec2ea chore: Release v5.33.0-dev.7 [skip ci]
# [5.33.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.6...v5.33.0-dev.7) (2025-08-03)

### Features

* **YouTube:** Add player button to change video quality ([#5435](https://github.com/ReVanced/revanced-patches/issues/5435)) ([7bdc328](7bdc32867a))
2025-08-03 15:26:39 +00:00
MarcaD
7bdc32867a feat(YouTube): Add player button to change video quality (#5435)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-08-03 11:23:46 -04:00
semantic-release-bot
6e60ac6963 chore: Release v5.33.0-dev.6 [skip ci]
# [5.33.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.5...v5.33.0-dev.6) (2025-07-31)

### Bug Fixes

* **YouTube - Video quality:** Use 1080p enhanced bitrate for Premium users ([#5565](https://github.com/ReVanced/revanced-patches/issues/5565)) ([1adbd56](1adbd563b2))
2025-07-31 18:30:03 +00:00
LisoUseInAIKyrios
1adbd563b2 fix(YouTube - Video quality): Use 1080p enhanced bitrate for Premium users (#5565) 2025-07-31 14:27:17 -04:00
github-actions[bot]
9ccf13b680 chore: Sync translations (#5567) 2025-07-31 14:27:05 -04:00
semantic-release-bot
7b8ca9c018 chore: Release v5.33.0-dev.5 [skip ci]
# [5.33.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.4...v5.33.0-dev.5) (2025-07-31)

### Bug Fixes

* **YouTube - Litho filter:** Correctly filter identifier of older YouTube targets ([b1d164b](b1d164b446))
2025-07-31 10:35:51 +00:00
github-actions[bot]
ae6dd23d08 chore: Sync translations (#5564) 2025-07-31 06:33:31 -04:00
LisoUseInAIKyrios
b1d164b446 fix(YouTube - Litho filter): Correctly filter identifier of older YouTube targets 2025-07-31 06:33:12 -04:00
dependabot[bot]
87c39dd485 chore(deps-dev): Bump semantic-release from 24.2.6 to 24.2.7 (#5545) 2025-07-30 10:31:08 -04:00
semantic-release-bot
1549ac12aa chore: Release v5.33.0-dev.4 [skip ci]
# [5.33.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.3...v5.33.0-dev.4) (2025-07-30)

### Performance Improvements

* **YouTube:** Filter identifier callback only on root component creation ([#5558](https://github.com/ReVanced/revanced-patches/issues/5558)) ([5d08fdd](5d08fdddb8))
2025-07-30 13:21:43 +00:00
LisoUseInAIKyrios
5d08fdddb8 perf(YouTube): Filter identifier callback only on root component creation (#5558) 2025-07-30 09:18:20 -04:00
semantic-release-bot
98114e5bde chore: Release v5.33.0-dev.3 [skip ci]
# [5.33.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.2...v5.33.0-dev.3) (2025-07-30)

### Bug Fixes

* **YouTube - Playback speed:** Use old speed menu for player button if enabled ([a4817df](a4817dfdd0))
2025-07-30 10:06:04 +00:00
LisoUseInAIKyrios
a4817dfdd0 fix(YouTube - Playback speed): Use old speed menu for player button if enabled 2025-07-30 06:03:21 -04:00
semantic-release-bot
d4f05351e1 chore: Release v5.33.0-dev.2 [skip ci]
# [5.33.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.33.0-dev.1...v5.33.0-dev.2) (2025-07-29)

### Features

* **ORF ON:** Add `Remove root detection` patch ([#5551](https://github.com/ReVanced/revanced-patches/issues/5551)) ([d92362b](d92362b0d9))
2025-07-29 08:33:08 +00:00
abichinger
d92362b0d9 feat(ORF ON): Add Remove root detection patch (#5551) 2025-07-29 04:30:43 -04:00
github-actions[bot]
afc7c75df1 chore: Sync translations (#5555) 2025-07-29 04:29:42 -04:00
semantic-release-bot
f0d4e9bfb4 chore: Release v5.33.0-dev.1 [skip ci]
# [5.33.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.32.0...v5.33.0-dev.1) (2025-07-28)

### Features

* **YouTube - Playback speed:** Add "Restore old playback speed menu" option ([#5552](https://github.com/ReVanced/revanced-patches/issues/5552)) ([e9e4cf3](e9e4cf39b6))
2025-07-28 18:47:44 +00:00
LisoUseInAIKyrios
e9e4cf39b6 feat(YouTube - Playback speed): Add "Restore old playback speed menu" option (#5552) 2025-07-28 22:44:18 +04:00
semantic-release-bot
0579a9f760 chore: Release v5.32.0 [skip ci]
# [5.32.0](https://github.com/ReVanced/revanced-patches/compare/v5.31.2...v5.32.0) (2025-07-27)

### Bug Fixes

* **Messenger - Hide inbox ads:** Support the latest app version ([8ec857a](8ec857a175))
* **YouTube  - Hide layout components:** Fix "Hide ticket shelf" ([#5516](https://github.com/ReVanced/revanced-patches/issues/5516)) ([9ddb3ac](9ddb3ac39d))
* **YouTube - GmsCore support:** Fix search suggestions when logged out by using correct search provider ([#5483](https://github.com/ReVanced/revanced-patches/issues/5483)) ([e4e81b8](e4e81b89ea))

### Features

* **Prime Video:** Add `Playback speed` patch ([#5444](https://github.com/ReVanced/revanced-patches/issues/5444)) ([f46dbcd](f46dbcd084))
* **YouTube - External downloads:** Improve the selection of the external downloader package ([#5504](https://github.com/ReVanced/revanced-patches/issues/5504)) ([cfd7780](cfd77800d6))
* **YT Music:** Support latest versions ([#5524](https://github.com/ReVanced/revanced-patches/issues/5524)) ([1258555](125855540b))
2025-07-27 13:17:58 +00:00
LisoUseInAIKyrios
1c0acef3f3 chore: Merge branch dev to main (#5479) 2025-07-27 17:14:36 +04:00
github-actions[bot]
2419adb77b chore: Sync translations (#5544) 2025-07-27 17:14:11 +04:00
semantic-release-bot
9e4113555b chore: Release v5.32.0-dev.5 [skip ci]
# [5.32.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.32.0-dev.4...v5.32.0-dev.5) (2025-07-26)

### Features

* **YT Music:** Support latest versions ([#5524](https://github.com/ReVanced/revanced-patches/issues/5524)) ([1258555](125855540b))
2025-07-26 06:30:30 +00:00
netceil
125855540b feat(YT Music): Support latest versions (#5524) 2025-07-26 10:27:47 +04:00
github-actions[bot]
a8eee825e6 chore: Sync translations (#5538) 2025-07-26 10:27:17 +04:00
semantic-release-bot
63859f0ef9 chore: Release v5.32.0-dev.4 [skip ci]
# [5.32.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.32.0-dev.3...v5.32.0-dev.4) (2025-07-25)

### Bug Fixes

* **Messenger - Hide inbox ads:** Support the latest app version ([8ec857a](8ec857a175))
2025-07-25 06:53:39 +00:00
github-actions[bot]
1c9000dbda chore: Sync translations (#5531) 2025-07-25 10:51:05 +04:00
LisoUseInAIKyrios
8ec857a175 fix(Messenger - Hide inbox ads): Support the latest app version 2025-07-25 10:46:10 +04:00
semantic-release-bot
f56c7868f5 chore: Release v5.32.0-dev.3 [skip ci]
# [5.32.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.32.0-dev.2...v5.32.0-dev.3) (2025-07-24)

### Features

* **YouTube - External downloads:** Improve the selection of the external downloader package ([#5504](https://github.com/ReVanced/revanced-patches/issues/5504)) ([cfd7780](cfd77800d6))
2025-07-24 07:31:13 +00:00
MarcaD
cfd77800d6 feat(YouTube - External downloads): Improve the selection of the external downloader package (#5504)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-07-24 11:28:16 +04:00
semantic-release-bot
707deaef0b chore: Release v5.32.0-dev.2 [skip ci]
# [5.32.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.32.0-dev.1...v5.32.0-dev.2) (2025-07-23)

### Bug Fixes

* **YouTube  - Hide layout components:** Fix "Hide ticket shelf" ([#5516](https://github.com/ReVanced/revanced-patches/issues/5516)) ([9ddb3ac](9ddb3ac39d))
2025-07-23 12:05:24 +00:00
ILoveOpenSourceApplications
9ddb3ac39d fix(YouTube - Hide layout components): Fix "Hide ticket shelf" (#5516) 2025-07-23 16:02:53 +04:00
github-actions[bot]
a7d3b7c287 chore: Sync translations (#5519) 2025-07-23 16:02:21 +04:00
LisoUseInAIKyrios
30bac0397e chore(YouTube): Fix string typo 2025-07-20 15:38:40 +04:00
semantic-release-bot
c5fc187a35 chore: Release v5.32.0-dev.1 [skip ci]
# [5.32.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.3-dev.1...v5.32.0-dev.1) (2025-07-16)

### Features

* **Prime Video:** Add `Playback speed` patch ([#5444](https://github.com/ReVanced/revanced-patches/issues/5444)) ([f46dbcd](f46dbcd084))
2025-07-16 19:30:50 +00:00
Sujitha Wijewantha
f46dbcd084 feat(Prime Video): Add Playback speed patch (#5444) 2025-07-16 23:27:55 +04:00
github-actions[bot]
2136573cb6 chore: Sync translations (#5484) 2025-07-16 23:27:18 +04:00
MarcaD
86ec08993c refactor(YouTube - Settings): Back button/gesture closes search instead of exiting (#5439) 2025-07-16 23:26:20 +04:00
semantic-release-bot
44da5a71c5 chore: Release v5.31.3-dev.1 [skip ci]
## [5.31.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.2...v5.31.3-dev.1) (2025-07-16)

### Bug Fixes

* **YouTube - GmsCore support:** Fix search suggestions when logged out by using correct search provider ([#5483](https://github.com/ReVanced/revanced-patches/issues/5483)) ([e4e81b8](e4e81b89ea))
2025-07-16 19:16:27 +00:00
sm455
e4e81b89ea fix(YouTube - GmsCore support): Fix search suggestions when logged out by using correct search provider (#5483) 2025-07-16 23:13:22 +04:00
LisoUseInAIKyrios
165df659a1 chore(YouTube): Add string contexts 2025-07-16 12:02:47 +04:00
LisoUseInAIKyrios
bb87afe0f6 ci: Revert "Group all Dependabot update into one PR (#5336)"
This reverts commit e019f83232.
2025-07-16 11:54:40 +04:00
semantic-release-bot
ac5fb17937 chore: Release v5.31.2 [skip ci]
## [5.31.2](https://github.com/ReVanced/revanced-patches/compare/v5.31.1...v5.31.2) (2025-07-14)

### Bug Fixes

* **Spotify - Spoof client:** Fix login failing by spoofing login request in addition ([#5448](https://github.com/ReVanced/revanced-patches/issues/5448)) ([c972267](c972267cd8))
* **YouTube - Disable double tap actions:** Remove old incompatible targets ([294b2dc](294b2dce2e))
* **YouTube - Hide layout components:** Hide quick actions does not work ([#5423](https://github.com/ReVanced/revanced-patches/issues/5423)) ([cc6984e](cc6984e919))
* **YouTube - Hide layout components:** Show correct custom header logo if 'Hide YouTube Doodles' is enabled ([#5431](https://github.com/ReVanced/revanced-patches/issues/5431)) ([19bc5b6](19bc5b63c5))
* **YouTube - Settings:** Back button/gesture closes search instead of exiting ([#5418](https://github.com/ReVanced/revanced-patches/issues/5418)) ([f994264](f994264d9c))
2025-07-14 12:02:46 +00:00
oSumAtrIX
e88356b3c5 chore: Merge branch dev to main (#5428) 2025-07-14 13:59:59 +02:00
github-actions[bot]
dead9c2d94 chore: Sync translations (#5449)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-07-14 13:59:35 +02:00
semantic-release-bot
ca640b2839 chore: Release v5.31.2-dev.5 [skip ci]
## [5.31.2-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.31.2-dev.4...v5.31.2-dev.5) (2025-07-14)

### Bug Fixes

* **Spotify - Spoof client:** Fix login failing by spoofing login request in addition ([#5448](https://github.com/ReVanced/revanced-patches/issues/5448)) ([c972267](c972267cd8))
2025-07-14 11:58:39 +00:00
oSumAtrIX
c972267cd8 fix(Spotify - Spoof client): Fix login failing by spoofing login request in addition (#5448) 2025-07-14 13:55:37 +02:00
ILoveOpenSourceApplications
d0d2c13d16 refactor(YouTube): Sort and standardize strings (#5442) 2025-07-14 15:01:10 +04:00
semantic-release-bot
e7b4ab53cf chore: Release v5.31.2-dev.4 [skip ci]
## [5.31.2-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.31.2-dev.3...v5.31.2-dev.4) (2025-07-13)

### Bug Fixes

* **YouTube - Settings:** Back button/gesture closes search instead of exiting ([#5418](https://github.com/ReVanced/revanced-patches/issues/5418)) ([f994264](f994264d9c))
2025-07-13 10:59:17 +00:00
MarcaD
f994264d9c fix(YouTube - Settings): Back button/gesture closes search instead of exiting (#5418) 2025-07-13 14:56:30 +04:00
github-actions[bot]
eb61c1f5d1 chore: Sync translations (#5437) 2025-07-13 14:55:36 +04:00
semantic-release-bot
e578347277 chore: Release v5.31.2-dev.3 [skip ci]
## [5.31.2-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.31.2-dev.2...v5.31.2-dev.3) (2025-07-13)

### Bug Fixes

* **YouTube - Disable double tap actions:** Remove old incompatible targets ([294b2dc](294b2dce2e))
2025-07-13 06:18:39 +00:00
LisoUseInAIKyrios
294b2dce2e fix(YouTube - Disable double tap actions): Remove old incompatible targets 2025-07-13 10:15:16 +04:00
github-actions[bot]
aa37105ea3 chore: Sync translations (#5436) 2025-07-13 10:03:04 +04:00
semantic-release-bot
eb57a2697b chore: Release v5.31.2-dev.2 [skip ci]
## [5.31.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.31.2-dev.1...v5.31.2-dev.2) (2025-07-12)

### Bug Fixes

* **YouTube - Hide layout components:** Show correct custom header logo if 'Hide YouTube Doodles' is enabled ([#5431](https://github.com/ReVanced/revanced-patches/issues/5431)) ([19bc5b6](19bc5b63c5))
2025-07-12 14:37:52 +00:00
LisoUseInAIKyrios
19bc5b63c5 fix(YouTube - Hide layout components): Show correct custom header logo if 'Hide YouTube Doodles' is enabled (#5431) 2025-07-12 18:34:29 +04:00
semantic-release-bot
2b93ff6cfc chore: Release v5.31.2-dev.1 [skip ci]
## [5.31.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.1...v5.31.2-dev.1) (2025-07-12)

### Bug Fixes

* **YouTube - Hide layout components:** Hide quick actions does not work ([#5423](https://github.com/ReVanced/revanced-patches/issues/5423)) ([cc6984e](cc6984e919))
2025-07-12 09:46:21 +00:00
MarcaD
cc6984e919 fix(YouTube - Hide layout components): Hide quick actions does not work (#5423) 2025-07-12 13:43:26 +04:00
github-actions[bot]
8bf575e778 chore: Sync translations (#5427) 2025-07-12 13:42:55 +04:00
semantic-release-bot
2e625ee1a2 chore: Release v5.31.1 [skip ci]
## [5.31.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.0...v5.31.1) (2025-07-11)

### Bug Fixes

* **Spotify - Unlock Premium:** Fix hiding context menu ads for latest version ([#5415](https://github.com/ReVanced/revanced-patches/issues/5415)) ([82255a0](82255a09d3))
2025-07-11 16:28:51 +00:00
oSumAtrIX
6bcba48ee7 chore: Merge branch dev to main (#5414) 2025-07-11 18:25:35 +02:00
semantic-release-bot
c3034edc43 chore: Release v5.31.1-dev.1 [skip ci]
## [5.31.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.31.0...v5.31.1-dev.1) (2025-07-11)

### Bug Fixes

* **Spotify - Unlock Premium:** Fix hiding context menu ads for latest version ([#5415](https://github.com/ReVanced/revanced-patches/issues/5415)) ([82255a0](82255a09d3))
2025-07-11 16:25:25 +00:00
Nuckyz
82255a09d3 fix(Spotify - Unlock Premium): Fix hiding context menu ads for latest version (#5415) 2025-07-11 18:21:49 +02:00
LisoUseInAIKyrios
594dce13cd chore(YouTube): Adjust settings UI text to not clip/wrap 2025-07-11 20:05:52 +04:00
semantic-release-bot
479e205808 chore: Release v5.31.0 [skip ci]
# [5.31.0](https://github.com/ReVanced/revanced-patches/compare/v5.30.0...v5.31.0) (2025-07-11)

### Bug Fixes

* **Bacon Reader - Spoof client:** Use www instead of ssl API to fix auth related issues  ([#5402](https://github.com/ReVanced/revanced-patches/issues/5402)) ([37a8682](37a8682901))
* Correctly name `Enable ROM signature spoofing` patch ([bd2a939](bd2a939a72))
* Fix accidental changes ([42195b9](42195b9f63))
* Fix refactoring typo ([b0129d3](b0129d383a))
* Handle empty list of announcements ([eafe3df](eafe3dfc45))
* **SoundCloud:** Constrain patches to last working app target ([89ec5d5](89ec5d5bc6))
* **Spotify - Unlock Premium:** Remove wrongfully hidden non ad browse sections ([#5403](https://github.com/ReVanced/revanced-patches/issues/5403)) ([b3e6c21](b3e6c215cc))
* **Spotify:** Remove other ads type from the browse screen ([#5333](https://github.com/ReVanced/revanced-patches/issues/5333)) ([4c8cfc8](4c8cfc8800))
* **Sync for Reddit - Spoof client:** Use www instead of ssl API to fix auth related issues ([#5392](https://github.com/ReVanced/revanced-patches/issues/5392)) ([6412a5c](6412a5cb1a))
* **YouTube - Hide ads:** Hide new type of general ad ([#5345](https://github.com/ReVanced/revanced-patches/issues/5345)) ([f9abec3](f9abec358a))
* **YouTube - Hide layout components:** Do not hide playlist sort button if 'Hide AI comments summary' is on ([cc4aef8](cc4aef89d3))
* **YouTube - Playback speed:** Allow custom speeds with 0.01x precision ([#5360](https://github.com/ReVanced/revanced-patches/issues/5360)) ([10f4464](10f4464735))
* **YouTube - Slide to seek:** Show tap and hold 2x speed overlay when active ([#5398](https://github.com/ReVanced/revanced-patches/issues/5398)) ([6833d37](6833d37c26))

### Features

* **Cricbuzz - Hide ads:** Hide Cricbuzz11 UI elements ([#5381](https://github.com/ReVanced/revanced-patches/issues/5381)) ([a3d47e7](a3d47e72e3))
* **Lightroom:** Constrain patches to last working version ([#5335](https://github.com/ReVanced/revanced-patches/issues/5335)) ([f7f49b8](f7f49b834e))
* **Spotify - Spoof client:** Fix issues like songs skipping by spoofing to iOS ([#5388](https://github.com/ReVanced/revanced-patches/issues/5388)) ([65cbf3c](65cbf3c1eb))
* **Spotify:** Remove support for old versions ([#5404](https://github.com/ReVanced/revanced-patches/issues/5404)) ([c9cc3d5](c9cc3d5c41))
* **YouTube - Change header:** Add in-app setting to change the app header ([#5346](https://github.com/ReVanced/revanced-patches/issues/5346)) ([4e74207](4e742075f3))
* **YouTube - Hide layout components:** Add `Hide channel links preview` and `Hide 'Visit Community' button` in channel page ([#5320](https://github.com/ReVanced/revanced-patches/issues/5320)) ([3eac215](3eac215e13))
* **YouTube:** Disable two-finger tap gesture for skipping chapters ([#5374](https://github.com/ReVanced/revanced-patches/issues/5374)) ([61c1a7a](61c1a7a75a))
2025-07-11 15:58:36 +00:00
oSumAtrIX
3d1b7e8101 chore: Merge branch dev to main (#5339) 2025-07-11 17:54:40 +02:00
LisoUseInAIKyrios
e951184b7a chore: Fix announcement url encoding 2025-07-11 19:51:19 +04:00
github-actions[bot]
d088b1e7ed chore: Sync translations (#5411) 2025-07-11 19:48:19 +04:00
semantic-release-bot
a38f635514 chore: Release v5.31.0-dev.17 [skip ci]
# [5.31.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.16...v5.31.0-dev.17) (2025-07-11)

### Bug Fixes

* **Spotify - Unlock Premium:** Remove wrongfully hidden non ad browse sections ([#5403](https://github.com/ReVanced/revanced-patches/issues/5403)) ([b3e6c21](b3e6c215cc))

### Features

* **Spotify:** Remove support for old versions ([#5404](https://github.com/ReVanced/revanced-patches/issues/5404)) ([c9cc3d5](c9cc3d5c41))
2025-07-11 15:41:53 +00:00
Nuckyz
b3e6c215cc fix(Spotify - Unlock Premium): Remove wrongfully hidden non ad browse sections (#5403) 2025-07-11 17:38:33 +02:00
Nuckyz
c9cc3d5c41 feat(Spotify): Remove support for old versions (#5404) 2025-07-11 17:37:59 +02:00
semantic-release-bot
536e64565c chore: Release v5.31.0-dev.16 [skip ci]
# [5.31.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.15...v5.31.0-dev.16) (2025-07-11)

### Features

* **Spotify - Spoof client:** Fix issues like songs skipping by spoofing to iOS ([#5388](https://github.com/ReVanced/revanced-patches/issues/5388)) ([65cbf3c](65cbf3c1eb))
* **YouTube:** Disable two-finger tap gesture for skipping chapters ([#5374](https://github.com/ReVanced/revanced-patches/issues/5374)) ([61c1a7a](61c1a7a75a))
2025-07-11 15:37:29 +00:00
Dawid Krajcarz
65cbf3c1eb feat(Spotify - Spoof client): Fix issues like songs skipping by spoofing to iOS (#5388)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-07-11 17:34:02 +02:00
abel1502
61c1a7a75a feat(YouTube): Disable two-finger tap gesture for skipping chapters (#5374)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-07-11 17:32:59 +02:00
Pun Butrach
1e39db06b8 ci: Remove fetch-depth from checkout (#5311) 2025-07-11 17:31:12 +02:00
Pun Butrach
e019f83232 ci: Group all Dependabot update into one PR (#5336) 2025-07-11 17:31:03 +02:00
semantic-release-bot
3b57a5f8c0 chore: Release v5.31.0-dev.15 [skip ci]
# [5.31.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.14...v5.31.0-dev.15) (2025-07-11)

### Bug Fixes

* Handle empty list of announcements ([eafe3df](eafe3dfc45))
2025-07-11 09:31:21 +00:00
oSumAtrIX
eafe3dfc45 fix: Handle empty list of announcements 2025-07-11 11:28:13 +02:00
semantic-release-bot
d56d8d990c chore: Release v5.31.0-dev.14 [skip ci]
# [5.31.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.13...v5.31.0-dev.14) (2025-07-10)

### Bug Fixes

* **Bacon Reader - Spoof client:** Use www instead of ssl API to fix auth related issues  ([#5402](https://github.com/ReVanced/revanced-patches/issues/5402)) ([37a8682](37a8682901))
2025-07-10 18:51:55 +00:00
Chirag Gada
37a8682901 fix(Bacon Reader - Spoof client): Use www instead of ssl API to fix auth related issues (#5402) 2025-07-10 20:49:04 +02:00
semantic-release-bot
11ba7d4e3e chore: Release v5.31.0-dev.13 [skip ci]
# [5.31.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.12...v5.31.0-dev.13) (2025-07-10)

### Bug Fixes

* **YouTube - Slide to seek:** Show tap and hold 2x speed overlay when active ([#5398](https://github.com/ReVanced/revanced-patches/issues/5398)) ([6833d37](6833d37c26))
2025-07-10 13:38:38 +00:00
LisoUseInAIKyrios
6833d37c26 fix(YouTube - Slide to seek): Show tap and hold 2x speed overlay when active (#5398) 2025-07-10 17:35:08 +04:00
github-actions[bot]
e6f72bcb7d chore: Sync translations (#5399) 2025-07-10 17:34:47 +04:00
LisoUseInAIKyrios
e8a227c082 chore: Fix api dump 2025-07-10 15:15:34 +04:00
semantic-release-bot
0472ec2830 chore: Release v5.31.0-dev.12 [skip ci]
# [5.31.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.11...v5.31.0-dev.12) (2025-07-09)

### Bug Fixes

* **Sync for Reddit - Spoof client:** Use www instead of ssl API to fix auth related issues ([#5392](https://github.com/ReVanced/revanced-patches/issues/5392)) ([6412a5c](6412a5cb1a))
2025-07-09 18:28:47 +00:00
oSumAtrIX
6412a5cb1a fix(Sync for Reddit - Spoof client): Use www instead of ssl API to fix auth related issues (#5392) 2025-07-09 20:25:48 +02:00
semantic-release-bot
cc548689ac chore: Release v5.31.0-dev.11 [skip ci]
# [5.31.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.10...v5.31.0-dev.11) (2025-07-09)

### Features

* **Cricbuzz - Hide ads:** Hide Cricbuzz11 UI elements ([#5381](https://github.com/ReVanced/revanced-patches/issues/5381)) ([a3d47e7](a3d47e72e3))
2025-07-09 17:50:37 +00:00
hoodles
a3d47e72e3 feat(Cricbuzz - Hide ads): Hide Cricbuzz11 UI elements (#5381) 2025-07-09 21:47:10 +04:00
semantic-release-bot
f37482443a chore: Release v5.31.0-dev.10 [skip ci]
# [5.31.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.9...v5.31.0-dev.10) (2025-07-09)

### Bug Fixes

* **YouTube - Hide layout components:** Do not hide playlist sort button if 'Hide AI comments summary' is on ([cc4aef8](cc4aef89d3))
2025-07-09 14:37:19 +00:00
LisoUseInAIKyrios
cc4aef89d3 fix(YouTube - Hide layout components): Do not hide playlist sort button if 'Hide AI comments summary' is on 2025-07-09 18:33:24 +04:00
github-actions[bot]
1c0a0eb4b5 chore: Sync translations (#5389) 2025-07-09 18:33:07 +04:00
semantic-release-bot
b1d6c46763 chore: Release v5.31.0-dev.9 [skip ci]
# [5.31.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.8...v5.31.0-dev.9) (2025-07-07)

### Bug Fixes

* Fix accidental changes ([42195b9](42195b9f63))
2025-07-07 10:32:07 +00:00
oSumAtrIX
42195b9f63 fix: Fix accidental changes 2025-07-07 12:29:21 +02:00
semantic-release-bot
a4e08ea13d chore: Release v5.31.0-dev.8 [skip ci]
# [5.31.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.7...v5.31.0-dev.8) (2025-07-07)

### Bug Fixes

* Correctly name `Enable ROM signature spoofing` patch ([bd2a939](bd2a939a72))
2025-07-07 07:43:53 +00:00
oSumAtrIX
bd2a939a72 fix: Correctly name Enable ROM signature spoofing patch 2025-07-07 09:40:28 +02:00
semantic-release-bot
a89179ab79 chore: Release v5.31.0-dev.7 [skip ci]
# [5.31.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.6...v5.31.0-dev.7) (2025-07-06)

### Bug Fixes

* Fix refactoring typo ([b0129d3](b0129d383a))
2025-07-06 14:22:39 +00:00
LisoUseInAIKyrios
b0129d383a fix: Fix refactoring typo 2025-07-06 18:19:43 +04:00
semantic-release-bot
23b6c42630 chore: Release v5.31.0-dev.6 [skip ci]
# [5.31.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.5...v5.31.0-dev.6) (2025-07-06)

### Bug Fixes

* **YouTube - Playback speed:** Allow custom speeds with 0.01x precision ([#5360](https://github.com/ReVanced/revanced-patches/issues/5360)) ([10f4464](10f4464735))
2025-07-06 13:16:35 +00:00
LisoUseInAIKyrios
10f4464735 fix(YouTube - Playback speed): Allow custom speeds with 0.01x precision (#5360) 2025-07-06 17:13:31 +04:00
github-actions[bot]
4e5addbba5 chore: Sync translations (#5369) 2025-07-06 17:12:43 +04:00
LisoUseInAIKyrios
8d11ede927 chore: Fix resource compile errors from last refactor 2025-07-06 17:07:19 +04:00
ILoveOpenSourceApplications
83a3f4da00 refactor: Standardize string formatting and apply alphabetical sorting (#5343) 2025-07-06 12:24:25 +04:00
LisoUseInAIKyrios
caf3b69731 refactor(YouTube - Change header): Handle importing bad settings data 2025-07-05 13:03:41 +04:00
LisoUseInAIKyrios
3135203b55 chore: Set untranslatable strings as untranslatable 2025-07-05 12:33:07 +04:00
semantic-release-bot
8d113a7c67 chore: Release v5.31.0-dev.5 [skip ci]
# [5.31.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.4...v5.31.0-dev.5) (2025-07-05)

### Features

* **YouTube - Change header:** Add in-app setting to change the app header ([#5346](https://github.com/ReVanced/revanced-patches/issues/5346)) ([4e74207](4e742075f3))
2025-07-05 08:06:28 +00:00
LisoUseInAIKyrios
4e742075f3 feat(YouTube - Change header): Add in-app setting to change the app header (#5346) 2025-07-05 12:02:58 +04:00
github-actions[bot]
04caa66662 chore: Sync translations (#5350) 2025-07-05 12:02:36 +04:00
semantic-release-bot
dacc85f5e7 chore: Release v5.31.0-dev.4 [skip ci]
# [5.31.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.3...v5.31.0-dev.4) (2025-07-04)

### Bug Fixes

* **YouTube - Hide ads:** Hide new type of general ad ([#5345](https://github.com/ReVanced/revanced-patches/issues/5345)) ([f9abec3](f9abec358a))
2025-07-04 20:09:13 +00:00
ILoveOpenSourceApplications
f9abec358a fix(YouTube - Hide ads): Hide new type of general ad (#5345) 2025-07-05 00:06:30 +04:00
github-actions[bot]
7e11514cc1 chore: Sync translations (#5347) 2025-07-05 00:06:16 +04:00
semantic-release-bot
2e9c8df8f6 chore: Release v5.31.0-dev.3 [skip ci]
# [5.31.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.2...v5.31.0-dev.3) (2025-07-04)

### Bug Fixes

* **Spotify:** Remove other ads type from the browse screen ([#5333](https://github.com/ReVanced/revanced-patches/issues/5333)) ([4c8cfc8](4c8cfc8800))
2025-07-04 08:44:24 +00:00
brosssh
4c8cfc8800 fix(Spotify): Remove other ads type from the browse screen (#5333) 2025-07-04 12:41:30 +04:00
semantic-release-bot
0ba6fad33f chore: Release v5.31.0-dev.2 [skip ci]
# [5.31.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.31.0-dev.1...v5.31.0-dev.2) (2025-07-04)

### Features

* **YouTube - Hide layout components:** Add `Hide channel links preview` and `Hide 'Visit Community' button` in channel page ([#5320](https://github.com/ReVanced/revanced-patches/issues/5320)) ([3eac215](3eac215e13))
2025-07-04 08:35:55 +00:00
ILoveOpenSourceApplications
3eac215e13 feat(YouTube - Hide layout components): Add Hide channel links preview and Hide 'Visit Community' button in channel page (#5320) 2025-07-04 12:32:48 +04:00
semantic-release-bot
90a3262f68 chore: Release v5.31.0-dev.1 [skip ci]
# [5.31.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.30.0...v5.31.0-dev.1) (2025-07-04)

### Bug Fixes

* **SoundCloud:** Constrain patches to last working app target ([89ec5d5](89ec5d5bc6))

### Features

* **Lightroom:** Constrain patches to last working version ([#5335](https://github.com/ReVanced/revanced-patches/issues/5335)) ([f7f49b8](f7f49b834e))
2025-07-04 08:32:35 +00:00
LisoUseInAIKyrios
f7f49b834e feat(Lightroom): Constrain patches to last working version (#5335) 2025-07-04 12:29:45 +04:00
LisoUseInAIKyrios
89ec5d5bc6 fix(SoundCloud): Constrain patches to last working app target 2025-07-04 12:28:58 +04:00
LisoUseInAIKyrios
e3bc8be936 chore(YouTube - Video Quality): Fix setting parent typo 2025-07-04 01:25:56 +04:00
semantic-release-bot
6c5c3f5a4d chore: Release v5.30.0 [skip ci]
# [5.30.0](https://github.com/ReVanced/revanced-patches/compare/v5.29.0...v5.30.0) (2025-07-02)

### Bug Fixes

* **Spotify - Spoof client patch:** Block sending bad integrity verdicts to potentially fix account suspensions ([#5274](https://github.com/ReVanced/revanced-patches/issues/5274)) ([69600d0](69600d08a4))
* **Spotify - Spoof client:** Handle remaining edge cases to obtain a session ([#5285](https://github.com/ReVanced/revanced-patches/issues/5285)) ([b2e601f](b2e601f0f0))
* **Spotify - Spoof client:** Skip native login screens ([#5228](https://github.com/ReVanced/revanced-patches/issues/5228)) ([d7ed325](d7ed32571f))
* **Spotify - Unlock Premium:** Fix hiding context menu ads on newest versions ([#5318](https://github.com/ReVanced/revanced-patches/issues/5318)) ([8b9e044](8b9e04475d))
* **Spotify - Unlock Premium:** Fix hiding context menu ads on newest versions by simplifying fingerprint ([#5318](https://github.com/ReVanced/revanced-patches/issues/5318)) ([d1313e3](d1313e3ea1))
* **Spotify:** Add `Spoof client` patch to fix various issues by using a web platform access token ([#5173](https://github.com/ReVanced/revanced-patches/issues/5173)) ([1a8aacd](1a8aacdff6))
* **YouTube - Hide ads:** Fix "Hide shopping links" ([#5267](https://github.com/ReVanced/revanced-patches/issues/5267)) ([e169056](e169056b70))
* **YouTube - Hide layout components:** Fix "Hide AI Comments summary" in Comments ([#5284](https://github.com/ReVanced/revanced-patches/issues/5284)) ([f084743](f08474369b))
* **YouTube - Hide layout components:** Fix "Hide AI-generated video summary" in video description ([#5269](https://github.com/ReVanced/revanced-patches/issues/5269)) ([ca694c7](ca694c78d2))
* **YouTube - Hide layout components:** Fix "Hide ticket shelf" hiding unwanted components ([#5292](https://github.com/ReVanced/revanced-patches/issues/5292)) ([ad6da67](ad6da67281))
* **YouTube - Hide Shorts components:** Fix hiding of untoggled components ([#5266](https://github.com/ReVanced/revanced-patches/issues/5266)) ([b6bf1e0](b6bf1e026c))
* **YouTube - SponsorBlock:** Do not show undo skip if PiP is active ([#5314](https://github.com/ReVanced/revanced-patches/issues/5314)) ([209a3a3](209a3a3626))

### Features

* **Spotify:** Remove ads section from browse ([#5193](https://github.com/ReVanced/revanced-patches/issues/5193)) ([92b588c](92b588c866))
* **YouTube - Hide layout components:** Add `Hide in history` option to filter bar ([#5271](https://github.com/ReVanced/revanced-patches/issues/5271)) ([da20e56](da20e565cd))
* **YouTube - SponsorBlock:** Add "Undo automatic skip toast" ([#5277](https://github.com/ReVanced/revanced-patches/issues/5277)) ([6ee94f8](6ee94f8532))
2025-07-02 14:55:17 +00:00
oSumAtrIX
629bd0644b chore: Merge branch dev to main (#5265) 2025-07-02 16:50:31 +02:00
github-actions[bot]
b4005079e3 chore: Sync translations (#5322) 2025-07-02 18:21:04 +04:00
semantic-release-bot
a354c443ad chore: Release v5.30.0-dev.10 [skip ci]
# [5.30.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.9...v5.30.0-dev.10) (2025-07-02)

### Bug Fixes

* **Spotify - Unlock Premium:** Fix hiding context menu ads on newest versions by simplifying fingerprint ([#5318](https://github.com/ReVanced/revanced-patches/issues/5318)) ([d1313e3](d1313e3ea1))
2025-07-02 14:08:17 +00:00
oSumAtrIX
d1313e3ea1 fix(Spotify - Unlock Premium): Fix hiding context menu ads on newest versions by simplifying fingerprint (#5318) 2025-07-02 16:04:26 +02:00
semantic-release-bot
11338008c6 chore: Release v5.30.0-dev.9 [skip ci]
# [5.30.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.8...v5.30.0-dev.9) (2025-07-02)

### Bug Fixes

* **Spotify - Unlock Premium:** Fix hiding context menu ads on newest versions ([#5318](https://github.com/ReVanced/revanced-patches/issues/5318)) ([8b9e044](8b9e04475d))
2025-07-02 12:12:04 +00:00
Nuckyz
8b9e04475d fix(Spotify - Unlock Premium): Fix hiding context menu ads on newest versions (#5318)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-07-02 14:08:11 +02:00
semantic-release-bot
d3c9dc6ed7 chore: Release v5.30.0-dev.8 [skip ci]
# [5.30.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.7...v5.30.0-dev.8) (2025-07-02)

### Bug Fixes

* **Spotify - Spoof client:** Skip native login screens ([#5228](https://github.com/ReVanced/revanced-patches/issues/5228)) ([d7ed325](d7ed32571f))
2025-07-02 10:23:13 +00:00
brosssh
d7ed32571f fix(Spotify - Spoof client): Skip native login screens (#5228)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: Dawid Krajcarz <80264606+drobotk@users.noreply.github.com>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-07-02 12:19:20 +02:00
semantic-release-bot
d3935f03c0 chore: Release v5.30.0-dev.7 [skip ci]
# [5.30.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.6...v5.30.0-dev.7) (2025-07-01)

### Bug Fixes

* **Spotify - Spoof client:** Handle remaining edge cases to obtain a session ([#5285](https://github.com/ReVanced/revanced-patches/issues/5285)) ([b2e601f](b2e601f0f0))
2025-07-01 21:15:22 +00:00
oSumAtrIX
b2e601f0f0 fix(Spotify - Spoof client): Handle remaining edge cases to obtain a session (#5285)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-07-01 23:11:05 +02:00
dependabot[bot]
d3ec219a29 chore(deps-dev): bump semantic-release from 24.2.5 to 24.2.6 (#5317) 2025-07-01 22:54:09 +04:00
semantic-release-bot
5ed07d4aaa chore: Release v5.30.0-dev.6 [skip ci]
# [5.30.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.5...v5.30.0-dev.6) (2025-07-01)

### Bug Fixes

* **YouTube - SponsorBlock:** Do not show undo skip if PiP is active ([#5314](https://github.com/ReVanced/revanced-patches/issues/5314)) ([209a3a3](209a3a3626))
2025-07-01 17:40:13 +00:00
LisoUseInAIKyrios
209a3a3626 fix(YouTube - SponsorBlock): Do not show undo skip if PiP is active (#5314) 2025-07-01 21:36:08 +04:00
github-actions[bot]
2b3419571f chore: Sync translations (#5315) 2025-07-01 21:35:50 +04:00
ILoveOpenSourceApplications
bbe504e616 refactor(YouTube): Match YouTube naming and sort strings (#5309) 2025-07-01 00:12:01 +04:00
semantic-release-bot
6c32591f62 chore: Release v5.30.0-dev.5 [skip ci]
# [5.30.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.4...v5.30.0-dev.5) (2025-06-30)

### Bug Fixes

* **YouTube - Hide layout components:** Fix "Hide ticket shelf" hiding unwanted components ([#5292](https://github.com/ReVanced/revanced-patches/issues/5292)) ([ad6da67](ad6da67281))
2025-06-30 08:01:39 +00:00
ILoveOpenSourceApplications
ad6da67281 fix(YouTube - Hide layout components): Fix "Hide ticket shelf" hiding unwanted components (#5292) 2025-06-30 11:58:01 +04:00
github-actions[bot]
14dc593eba chore: Sync translations (#5294) 2025-06-30 11:57:44 +04:00
semantic-release-bot
e52ee41222 chore: Release v5.30.0-dev.4 [skip ci]
# [5.30.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.3...v5.30.0-dev.4) (2025-06-30)

### Features

* **YouTube - SponsorBlock:** Add "Undo automatic skip toast" ([#5277](https://github.com/ReVanced/revanced-patches/issues/5277)) ([6ee94f8](6ee94f8532))
2025-06-30 06:54:53 +00:00
MarcaD
6ee94f8532 feat(YouTube - SponsorBlock): Add "Undo automatic skip toast" (#5277)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-06-30 10:50:52 +04:00
semantic-release-bot
21688201af chore: Release v5.30.0-dev.3 [skip ci]
# [5.30.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.2...v5.30.0-dev.3) (2025-06-28)

### Bug Fixes

* **YouTube - Hide layout components:** Fix "Hide AI Comments summary" in Comments ([#5284](https://github.com/ReVanced/revanced-patches/issues/5284)) ([f084743](f08474369b))
2025-06-28 18:05:53 +00:00
ILoveOpenSourceApplications
f08474369b fix(YouTube - Hide layout components): Fix "Hide AI Comments summary" in Comments (#5284) 2025-06-28 22:02:03 +04:00
LisoUseInAIKyrios
ed617094ea refactor(YouTube - Litho): Use a simpler hook that does not require using a thread local (#5281) 2025-06-28 11:51:29 +04:00
semantic-release-bot
9131c50f1b chore: Release v5.30.0-dev.2 [skip ci]
# [5.30.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.30.0-dev.1...v5.30.0-dev.2) (2025-06-27)

### Bug Fixes

* **Spotify - Spoof client patch:** Block sending bad integrity verdicts to potentially fix account suspensions ([#5274](https://github.com/ReVanced/revanced-patches/issues/5274)) ([69600d0](69600d08a4))
2025-06-27 14:07:00 +00:00
brosssh
69600d08a4 fix(Spotify - Spoof client patch): Block sending bad integrity verdicts to potentially fix account suspensions (#5274)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-06-27 16:03:07 +02:00
semantic-release-bot
5dba77612b chore: Release v5.30.0-dev.1 [skip ci]
# [5.30.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.29.1-dev.1...v5.30.0-dev.1) (2025-06-27)

### Bug Fixes

* **YouTube - Hide ads:** Fix "Hide shopping links" ([#5267](https://github.com/ReVanced/revanced-patches/issues/5267)) ([e169056](e169056b70))
* **YouTube - Hide layout components:** Fix "Hide AI-generated video summary" in video description ([#5269](https://github.com/ReVanced/revanced-patches/issues/5269)) ([ca694c7](ca694c78d2))
* **YouTube - Hide Shorts components:** Fix hiding of untoggled components ([#5266](https://github.com/ReVanced/revanced-patches/issues/5266)) ([b6bf1e0](b6bf1e026c))

### Features

* **Spotify:** Remove ads section from browse ([#5193](https://github.com/ReVanced/revanced-patches/issues/5193)) ([92b588c](92b588c866))
* **YouTube - Hide layout components:** Add `Hide in history` option to filter bar ([#5271](https://github.com/ReVanced/revanced-patches/issues/5271)) ([da20e56](da20e565cd))
2025-06-27 11:38:02 +00:00
brosssh
92b588c866 feat(Spotify): Remove ads section from browse (#5193) 2025-06-27 15:34:13 +04:00
ILoveOpenSourceApplications
da20e565cd feat(YouTube - Hide layout components): Add Hide in history option to filter bar (#5271) 2025-06-27 15:33:53 +04:00
ILoveOpenSourceApplications
ca694c78d2 fix(YouTube - Hide layout components): Fix "Hide AI-generated video summary" in video description (#5269) 2025-06-27 15:33:37 +04:00
ILoveOpenSourceApplications
e169056b70 fix(YouTube - Hide ads): Fix "Hide shopping links" (#5267) 2025-06-27 15:33:21 +04:00
ILoveOpenSourceApplications
b6bf1e026c fix(YouTube - Hide Shorts components): Fix hiding of untoggled components (#5266) 2025-06-27 15:33:02 +04:00
github-actions[bot]
9fa89d48c0 chore: Sync translations (#5272) 2025-06-27 15:32:34 +04:00
semantic-release-bot
5d2c21540c chore: Release v5.29.1-dev.1 [skip ci]
## [5.29.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.29.0...v5.29.1-dev.1) (2025-06-26)

### Bug Fixes

* **Spotify:** Add `Spoof client` patch to fix various issues by using a web platform access token ([#5173](https://github.com/ReVanced/revanced-patches/issues/5173)) ([1a8aacd](1a8aacdff6))
2025-06-26 17:56:10 +00:00
oSumAtrIX
1a8aacdff6 fix(Spotify): Add Spoof client patch to fix various issues by using a web platform access token (#5173)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: brosssh <tiabroch@gmail.com>
Co-authored-by: Dawid Krajcarz <80264606+drobotk@users.noreply.github.com>
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-06-26 19:51:18 +02:00
semantic-release-bot
1804bd9bfc chore: Release v5.29.0 [skip ci]
# [5.29.0](https://github.com/ReVanced/revanced-patches/compare/v5.28.0...v5.29.0) (2025-06-26)

### Bug Fixes

* Add scrollable content to modern style settings dialogs ([#5211](https://github.com/ReVanced/revanced-patches/issues/5211)) ([2b62fc2](2b62fc2224))
* **Google Photos:** Resolve startup crash for Android 5.0 devices ([7be3741](7be374100b))
* **YouTube - Hide ads:** Hide new type of product ad in video description ([#5225](https://github.com/ReVanced/revanced-patches/issues/5225)) ([b656976](b65697603d))
* **YouTube - Hide layout components:** Fix "Hide video description attributes" ([#5250](https://github.com/ReVanced/revanced-patches/issues/5250)) ([978c244](978c24458b))
* **YouTube - Hide Shorts components:** Fix "Hide Use this sound button" ([#5233](https://github.com/ReVanced/revanced-patches/issues/5233)) ([a678f17](a678f178e1))
* **YouTube - Hide Shorts components:** Fix "Hide Use this template button" ([#5249](https://github.com/ReVanced/revanced-patches/issues/5249)) ([957bece](957bece3e9))
* **YouTube:** Always use single threaded layout to resolve layout bugs in unpatched YouTube ([#5226](https://github.com/ReVanced/revanced-patches/issues/5226)) ([ccd1691](ccd169121a))
* **YouTube:** Fix refactoring app startup exception ([0dbd058](0dbd058099))

### Features

* Add `Spoof app signature` patch ([#5158](https://github.com/ReVanced/revanced-patches/issues/5158)) ([fb83e58](fb83e58f79))
* **Cricbuzz:** Add `Hide ads` patch ([#4998](https://github.com/ReVanced/revanced-patches/issues/4998)) ([558bf8b](558bf8bca8))
* **Crunchyroll:** Add `Hide ads` patch ([#5201](https://github.com/ReVanced/revanced-patches/issues/5201)) ([d338989](d338989cb4))
* **YouTube - Hide Shorts components:** Add `Hide Effects button` ([#5255](https://github.com/ReVanced/revanced-patches/issues/5255)) ([29c86ac](29c86ac6a3))
* **YouTube - Hide video action buttons:** Add `Hide Stop ads` ([#5245](https://github.com/ReVanced/revanced-patches/issues/5245)) ([0e63f49](0e63f49e13))
* **YouTube:** Add an option to disable toasts when changing default playback speed or quality ([#5230](https://github.com/ReVanced/revanced-patches/issues/5230)) ([6b719df](6b719dfcd7))
* **YouTube:** Support version `20.13.41` ([#5253](https://github.com/ReVanced/revanced-patches/issues/5253)) ([439ca37](439ca37e99))
2025-06-26 08:06:08 +00:00
LisoUseInAIKyrios
7eb4e62762 chore: Merge branch dev to main (#5227) 2025-06-26 12:02:33 +04:00
LisoUseInAIKyrios
b8e10b5c1f chore: Fix api dump 2025-06-26 11:51:54 +04:00
github-actions[bot]
a7c11b9b08 chore: Sync translations (#5258) 2025-06-26 11:50:50 +04:00
semantic-release-bot
443c0a74d5 chore: Release v5.29.0-dev.11 [skip ci]
# [5.29.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.10...v5.29.0-dev.11) (2025-06-26)

### Features

* **Cricbuzz:** Add `Hide ads` patch ([#4998](https://github.com/ReVanced/revanced-patches/issues/4998)) ([558bf8b](558bf8bca8))
2025-06-26 07:13:07 +00:00
github-actions[bot]
84a0f7f7d7 chore: Sync translations (#5257) 2025-06-26 11:10:05 +04:00
Sourav Agrawal
558bf8bca8 feat(Cricbuzz): Add Hide ads patch (#4998) 2025-06-26 11:08:22 +04:00
semantic-release-bot
e22d4e6a4b chore: Release v5.29.0-dev.10 [skip ci]
# [5.29.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.9...v5.29.0-dev.10) (2025-06-25)

### Features

* **YouTube - Hide Shorts components:** Add `Hide Effects button` ([#5255](https://github.com/ReVanced/revanced-patches/issues/5255)) ([29c86ac](29c86ac6a3))
2025-06-25 08:59:45 +00:00
LisoUseInAIKyrios
a07f946633 chore: Fix typo 2025-06-25 12:56:42 +04:00
LisoUseInAIKyrios
29c86ac6a3 feat(YouTube - Hide Shorts components): Add Hide Effects button (#5255) 2025-06-25 12:54:59 +04:00
semantic-release-bot
19cf5667d8 chore: Release v5.29.0-dev.9 [skip ci]
# [5.29.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.8...v5.29.0-dev.9) (2025-06-25)

### Features

* Add `Spoof app signature` patch ([#5158](https://github.com/ReVanced/revanced-patches/issues/5158)) ([fb83e58](fb83e58f79))
2025-06-25 07:16:33 +00:00
Markus Probst
fb83e58f79 feat: Add Spoof app signature patch (#5158) 2025-06-25 11:13:32 +04:00
semantic-release-bot
9844081d04 chore: Release v5.29.0-dev.8 [skip ci]
# [5.29.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.7...v5.29.0-dev.8) (2025-06-25)

### Features

* **YouTube:** Support version `20.13.41` ([#5253](https://github.com/ReVanced/revanced-patches/issues/5253)) ([439ca37](439ca37e99))
2025-06-25 07:06:01 +00:00
LisoUseInAIKyrios
439ca37e99 feat(YouTube): Support version 20.13.41 (#5253) 2025-06-25 11:03:25 +04:00
semantic-release-bot
113a3d9f19 chore: Release v5.29.0-dev.7 [skip ci]
# [5.29.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.6...v5.29.0-dev.7) (2025-06-24)

### Bug Fixes

* **YouTube - Hide layout components:** Fix "Hide video description attributes" ([#5250](https://github.com/ReVanced/revanced-patches/issues/5250)) ([978c244](978c24458b))
* **YouTube - Hide Shorts components:** Fix "Hide Use this template button" ([#5249](https://github.com/ReVanced/revanced-patches/issues/5249)) ([957bece](957bece3e9))
2025-06-24 18:50:18 +00:00
ILoveOpenSourceApplications
978c24458b fix(YouTube - Hide layout components): Fix "Hide video description attributes" (#5250) 2025-06-24 22:47:46 +04:00
ILoveOpenSourceApplications
957bece3e9 fix(YouTube - Hide Shorts components): Fix "Hide Use this template button" (#5249) 2025-06-24 22:47:05 +04:00
github-actions[bot]
d32c3ac51d chore: Sync translations (#5251) 2025-06-24 22:46:50 +04:00
LisoUseInAIKyrios
26102a70a2 chore: Fix compile warning 2025-06-24 22:43:25 +04:00
semantic-release-bot
2b44bf4c23 chore: Release v5.29.0-dev.6 [skip ci]
# [5.29.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.5...v5.29.0-dev.6) (2025-06-24)

### Features

* **YouTube - Hide video action buttons:** Add `Hide Stop ads` ([#5245](https://github.com/ReVanced/revanced-patches/issues/5245)) ([0e63f49](0e63f49e13))
2025-06-24 11:14:05 +00:00
ILoveOpenSourceApplications
0e63f49e13 feat(YouTube - Hide video action buttons): Add Hide Stop ads (#5245) 2025-06-24 15:10:23 +04:00
semantic-release-bot
674a5b8d29 chore: Release v5.29.0-dev.5 [skip ci]
# [5.29.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.4...v5.29.0-dev.5) (2025-06-23)

### Bug Fixes

* **Google Photos:** Resolve startup crash for Android 5.0 devices ([7be3741](7be374100b))
2025-06-23 12:28:49 +00:00
LisoUseInAIKyrios
7be374100b fix(Google Photos): Resolve startup crash for Android 5.0 devices 2025-06-23 16:24:42 +04:00
semantic-release-bot
e48c152b95 chore: Release v5.29.0-dev.4 [skip ci]
# [5.29.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.3...v5.29.0-dev.4) (2025-06-23)

### Bug Fixes

* **YouTube - Hide Shorts components:** Fix "Hide Use this sound button" ([#5233](https://github.com/ReVanced/revanced-patches/issues/5233)) ([a678f17](a678f178e1))
2025-06-23 09:33:13 +00:00
ILoveOpenSourceApplications
a678f178e1 fix(YouTube - Hide Shorts components): Fix "Hide Use this sound button" (#5233) 2025-06-23 13:29:53 +04:00
semantic-release-bot
2d8f5641f9 chore: Release v5.29.0-dev.3 [skip ci]
# [5.29.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.2...v5.29.0-dev.3) (2025-06-23)

### Bug Fixes

* **YouTube:** Fix refactoring app startup exception ([0dbd058](0dbd058099))
2025-06-23 09:18:27 +00:00
LisoUseInAIKyrios
0dbd058099 fix(YouTube): Fix refactoring app startup exception 2025-06-23 13:15:43 +04:00
semantic-release-bot
c1a8fd0766 chore: Release v5.29.0-dev.2 [skip ci]
# [5.29.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.29.0-dev.1...v5.29.0-dev.2) (2025-06-23)

### Features

* **Crunchyroll:** Add `Hide ads` patch ([#5201](https://github.com/ReVanced/revanced-patches/issues/5201)) ([d338989](d338989cb4))
2025-06-23 08:47:04 +00:00
hoodles
d338989cb4 feat(Crunchyroll): Add Hide ads patch (#5201) 2025-06-23 12:44:07 +04:00
github-actions[bot]
b94daacf01 chore: Sync translations (#5236) 2025-06-23 12:43:45 +04:00
semantic-release-bot
c764c4f197 chore: Release v5.29.0-dev.1 [skip ci]
# [5.29.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.28.1-dev.2...v5.29.0-dev.1) (2025-06-23)

### Bug Fixes

* **YouTube:** Always use single threaded layout to resolve layout bugs in unpatched YouTube ([#5226](https://github.com/ReVanced/revanced-patches/issues/5226)) ([ccd1691](ccd169121a))

### Features

* **YouTube:** Add an option to disable toasts when changing default playback speed or quality ([#5230](https://github.com/ReVanced/revanced-patches/issues/5230)) ([6b719df](6b719dfcd7))
2025-06-23 08:24:13 +00:00
MarcaD
6b719dfcd7 feat(YouTube): Add an option to disable toasts when changing default playback speed or quality (#5230) 2025-06-23 12:20:37 +04:00
LisoUseInAIKyrios
ccd169121a fix(YouTube): Always use single threaded layout to resolve layout bugs in unpatched YouTube (#5226) 2025-06-23 12:19:07 +04:00
semantic-release-bot
dcfbd8bf93 chore: Release v5.28.1-dev.2 [skip ci]
## [5.28.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.28.1-dev.1...v5.28.1-dev.2) (2025-06-23)

### Bug Fixes

* **YouTube - Hide ads:** Hide new type of product ad in video description ([#5225](https://github.com/ReVanced/revanced-patches/issues/5225)) ([b656976](b65697603d))
2025-06-23 07:19:38 +00:00
ILoveOpenSourceApplications
b65697603d fix(YouTube - Hide ads): Hide new type of product ad in video description (#5225) 2025-06-23 11:17:08 +04:00
semantic-release-bot
25da5cca8b chore: Release v5.28.1-dev.1 [skip ci]
## [5.28.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.28.0...v5.28.1-dev.1) (2025-06-22)

### Bug Fixes

* Add scrollable content to modern style settings dialogs ([#5211](https://github.com/ReVanced/revanced-patches/issues/5211)) ([2b62fc2](2b62fc2224))
2025-06-22 11:23:52 +00:00
MarcaD
2b62fc2224 fix: Add scrollable content to modern style settings dialogs (#5211) 2025-06-22 15:21:00 +04:00
semantic-release-bot
a9e9456b6b chore: Release v5.28.0 [skip ci]
# [5.28.0](https://github.com/ReVanced/revanced-patches/compare/v5.27.0...v5.28.0) (2025-06-20)

### Bug Fixes

* **Google Photos:** Resolve startup crash if MicroG GmsCore does not already have granted permissions ([1cea6bf](1cea6bfdff))
* **Messenger - Remove Meta AI:** Improve patch logic ([#5153](https://github.com/ReVanced/revanced-patches/issues/5153)) ([a8d2a1e](a8d2a1e028))
* **Pandora - Disable ads:** Support latest app target ([#5185](https://github.com/ReVanced/revanced-patches/issues/5185)) ([90868ff](90868ff025))
* **Spotify:** Fix `Hide Create button` and `Sanitize sharing links` for older but supported app targets ([#5159](https://github.com/ReVanced/revanced-patches/issues/5159)) ([5540136](55401368b8))
* **Threads - Hide ads:** Constrain patch to the last working app target ([#5189](https://github.com/ReVanced/revanced-patches/issues/5189)) ([e138501](e138501657))
* **YouTube:** Remove old app targets that are no longer supported by YouTube ([#5192](https://github.com/ReVanced/revanced-patches/issues/5192)) ([e790cfb](e790cfbf59))

### Features

* **Spotify:** Add `Change lyrics provider` patch ([#4937](https://github.com/ReVanced/revanced-patches/issues/4937)) ([7bbaca7](7bbaca77ad))
* Use modern style settings dialogs ([#5109](https://github.com/ReVanced/revanced-patches/issues/5109)) ([a426e2a](a426e2af50))
2025-06-20 08:17:57 +00:00
LisoUseInAIKyrios
b01523e97d chore: Merge branch dev to main (#5160) 2025-06-20 12:14:29 +04:00
github-actions[bot]
b8afb4e821 chore: Sync translations (#5210) 2025-06-20 12:13:39 +04:00
github-actions[bot]
0d2198faed chore: Sync translations (#5207) 2025-06-20 01:33:20 +04:00
semantic-release-bot
5c7c407b82 chore: Release v5.28.0-dev.8 [skip ci]
# [5.28.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.7...v5.28.0-dev.8) (2025-06-19)

### Bug Fixes

* **Messenger - Remove Meta AI:** Improve patch logic ([#5153](https://github.com/ReVanced/revanced-patches/issues/5153)) ([a8d2a1e](a8d2a1e028))
2025-06-19 06:10:06 +00:00
Dawid Krajcarz
a8d2a1e028 fix(Messenger - Remove Meta AI): Improve patch logic (#5153) 2025-06-19 10:06:46 +04:00
semantic-release-bot
d31624cae8 chore: Release v5.28.0-dev.7 [skip ci]
# [5.28.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.6...v5.28.0-dev.7) (2025-06-18)

### Bug Fixes

* **YouTube:** Remove old app targets that are no longer supported by YouTube ([#5192](https://github.com/ReVanced/revanced-patches/issues/5192)) ([e790cfb](e790cfbf59))
2025-06-18 10:38:43 +00:00
LisoUseInAIKyrios
e790cfbf59 fix(YouTube): Remove old app targets that are no longer supported by YouTube (#5192) 2025-06-18 12:35:43 +02:00
LisoUseInAIKyrios
a54d408d3e chore: Fix string typos, fix missing long/wide returnEarly/returnLate 2025-06-18 11:06:48 +02:00
semantic-release-bot
5d3769e921 chore: Release v5.28.0-dev.6 [skip ci]
# [5.28.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.5...v5.28.0-dev.6) (2025-06-17)

### Bug Fixes

* **Threads - Hide ads:** Constrain patch to the last working app target ([#5189](https://github.com/ReVanced/revanced-patches/issues/5189)) ([e138501](e138501657))
2025-06-17 21:07:00 +00:00
LisoUseInAIKyrios
e138501657 fix(Threads - Hide ads): Constrain patch to the last working app target (#5189) 2025-06-17 23:03:35 +02:00
semantic-release-bot
a9235d6b62 chore: Release v5.28.0-dev.5 [skip ci]
# [5.28.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.4...v5.28.0-dev.5) (2025-06-17)

### Bug Fixes

* **Pandora - Disable ads:** Support latest app target ([#5185](https://github.com/ReVanced/revanced-patches/issues/5185)) ([90868ff](90868ff025))
2025-06-17 06:47:11 +00:00
hoodles
90868ff025 fix(Pandora - Disable ads): Support latest app target (#5185) 2025-06-17 08:44:19 +02:00
github-actions[bot]
345ec5c430 chore: Sync translations (#5188) 2025-06-17 08:43:55 +02:00
semantic-release-bot
c8b95d475c chore: Release v5.28.0-dev.4 [skip ci]
# [5.28.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.3...v5.28.0-dev.4) (2025-06-13)

### Features

* Use modern style settings dialogs ([#5109](https://github.com/ReVanced/revanced-patches/issues/5109)) ([a426e2a](a426e2af50))
2025-06-13 07:33:27 +00:00
github-actions[bot]
0a93f44a5e chore: Sync translations (#5167) 2025-06-13 09:30:30 +02:00
MarcaD
a426e2af50 feat: Use modern style settings dialogs (#5109)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-06-13 09:29:13 +02:00
semantic-release-bot
9e30c34e74 chore: Release v5.28.0-dev.3 [skip ci]
# [5.28.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.2...v5.28.0-dev.3) (2025-06-11)

### Bug Fixes

* **Spotify:** Fix `Hide Create button` and `Sanitize sharing links` for older but supported app targets ([#5159](https://github.com/ReVanced/revanced-patches/issues/5159)) ([5540136](55401368b8))
2025-06-11 20:23:04 +00:00
Nuckyz
55401368b8 fix(Spotify): Fix Hide Create button and Sanitize sharing links for older but supported app targets (#5159) 2025-06-11 17:20:19 -03:00
LisoUseInAIKyrios
c0c56fef23 chore: Fix debug logging if context is not set 2025-06-11 19:57:37 +02:00
semantic-release-bot
69df47602f chore: Release v5.28.0-dev.2 [skip ci]
# [5.28.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.28.0-dev.1...v5.28.0-dev.2) (2025-06-11)

### Bug Fixes

* **Google Photos:** Resolve startup crash if MicroG GmsCore does not already have granted permissions ([1cea6bf](1cea6bfdff))
2025-06-11 17:44:07 +00:00
LisoUseInAIKyrios
1cea6bfdff fix(Google Photos): Resolve startup crash if MicroG GmsCore does not already have granted permissions 2025-06-11 19:40:37 +02:00
semantic-release-bot
e2a9552f91 chore: Release v5.28.0-dev.1 [skip ci]
# [5.28.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.27.0...v5.28.0-dev.1) (2025-06-11)

### Features

* **Spotify:** Add `Change lyrics provider` patch ([#4937](https://github.com/ReVanced/revanced-patches/issues/4937)) ([7bbaca7](7bbaca77ad))
2025-06-11 08:28:44 +00:00
brosssh
7bbaca77ad feat(Spotify): Add Change lyrics provider patch (#4937) 2025-06-11 10:25:58 +02:00
semantic-release-bot
246f3efe55 chore: Release v5.27.0 [skip ci]
# [5.27.0](https://github.com/ReVanced/revanced-patches/compare/v5.26.0...v5.27.0) (2025-06-09)

### Bug Fixes

* **Bandcamp - Remove play limits:** Support latest app version ([#5124](https://github.com/ReVanced/revanced-patches/issues/5124)) ([c0448de](c0448dece4))
* **Spotify:** `Hide Create button` patch failing in edge cases ([#5131](https://github.com/ReVanced/revanced-patches/issues/5131)) ([7a432e5](7a432e5741))
* **Spotify:** Prevent hiding all navigation bar buttons ([#5122](https://github.com/ReVanced/revanced-patches/issues/5122)) ([65fc6b4](65fc6b43f5))
* **YouTube - Hide layout components:** Remove broken option 'Hide comments emoji picker' ([#5121](https://github.com/ReVanced/revanced-patches/issues/5121)) ([4b8499f](4b8499ff2c))
* **YouTube - Hide Shorts components:** Disable A/B player flags that prevents hiding buttons ([9d10ab6](9d10ab6c00))
* **YouTube - Video quality:** Remove non-functional Shorts 144p default quality ([6aff8e8](6aff8e8ca4))

### Features

* Add `Hide app icon` patch ([#4977](https://github.com/ReVanced/revanced-patches/issues/4977)) ([6127f48](6127f48a9e))
* **Google Photos:** Add `Enable DCIM folders backup control` patch ([#5138](https://github.com/ReVanced/revanced-patches/issues/5138)) ([af827e2](af827e2f1a))
* **Messenger:** Add `Hide Facebook button` patch ([#5057](https://github.com/ReVanced/revanced-patches/issues/5057)) ([ed0d807](ed0d807d70))
* **YouTube - Hide player overlay buttons:** Add in app setting for "Hide player control buttons background" ([#5147](https://github.com/ReVanced/revanced-patches/issues/5147)) ([adfac8a](adfac8a1f2))
* **YouTube - Hide Shorts components:** Add hide 'New posts' button ([f8e31c8](f8e31c820a))
* **YouTube - Theme:** Add option for black and white splash screen animation ([#5119](https://github.com/ReVanced/revanced-patches/issues/5119)) ([6d5380d](6d5380d44d))
2025-06-09 18:37:59 +00:00
LisoUseInAIKyrios
0fca3e8fb1 chore: Merge branch dev to main (#5115) 2025-06-09 20:35:14 +02:00
semantic-release-bot
c09255eaed chore: Release v5.27.0-dev.9 [skip ci]
# [5.27.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.8...v5.27.0-dev.9) (2025-06-09)

### Features

* **Messenger:** Add `Hide Facebook button` patch ([#5057](https://github.com/ReVanced/revanced-patches/issues/5057)) ([ed0d807](ed0d807d70))
2025-06-09 18:18:19 +00:00
github-actions[bot]
e78d6240ea chore: Sync translations (#5151) 2025-06-09 20:15:28 +02:00
Dawid Krajcarz
ed0d807d70 feat(Messenger): Add Hide Facebook button patch (#5057) 2025-06-09 20:13:05 +02:00
semantic-release-bot
1c39004350 chore: Release v5.27.0-dev.8 [skip ci]
# [5.27.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.7...v5.27.0-dev.8) (2025-06-09)

### Features

* Add `Hide app icon` patch ([#4977](https://github.com/ReVanced/revanced-patches/issues/4977)) ([6127f48](6127f48a9e))
2025-06-09 14:11:00 +00:00
ILoveOpenSourceApplications
6127f48a9e feat: Add Hide app icon patch (#4977) 2025-06-09 11:07:43 -03:00
semantic-release-bot
ad416f4aa7 chore: Release v5.27.0-dev.7 [skip ci]
# [5.27.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.6...v5.27.0-dev.7) (2025-06-08)

### Features

* **YouTube - Hide player overlay buttons:** Add in app setting for "Hide player control buttons background" ([#5147](https://github.com/ReVanced/revanced-patches/issues/5147)) ([adfac8a](adfac8a1f2))
2025-06-08 18:07:53 +00:00
Nuckyz
adfac8a1f2 feat(YouTube - Hide player overlay buttons): Add in app setting for "Hide player control buttons background" (#5147) 2025-06-08 15:04:58 -03:00
semantic-release-bot
498488d45b chore: Release v5.27.0-dev.6 [skip ci]
# [5.27.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.5...v5.27.0-dev.6) (2025-06-08)

### Features

* **YouTube - Hide Shorts components:** Add hide 'New posts' button ([f8e31c8](f8e31c820a))
2025-06-08 12:06:28 +00:00
LisoUseInAIKyrios
f8e31c820a feat(YouTube - Hide Shorts components): Add hide 'New posts' button 2025-06-08 14:03:00 +02:00
semantic-release-bot
826a391591 chore: Release v5.27.0-dev.5 [skip ci]
# [5.27.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.4...v5.27.0-dev.5) (2025-06-08)

### Features

* **Google Photos:** Add `Enable DCIM folders backup control` patch ([#5138](https://github.com/ReVanced/revanced-patches/issues/5138)) ([af827e2](af827e2f1a))
2025-06-08 07:17:04 +00:00
Nuckyz
af827e2f1a feat(Google Photos): Add Enable DCIM folders backup control patch (#5138) 2025-06-08 09:13:53 +02:00
semantic-release-bot
97cd31509e chore: Release v5.27.0-dev.4 [skip ci]
# [5.27.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.3...v5.27.0-dev.4) (2025-06-06)

### Bug Fixes

* **Bandcamp - Remove play limits:** Support latest app version ([#5124](https://github.com/ReVanced/revanced-patches/issues/5124)) ([c0448de](c0448dece4))
2025-06-06 21:22:31 +00:00
hoodles
c0448dece4 fix(Bandcamp - Remove play limits): Support latest app version (#5124) 2025-06-06 23:20:00 +02:00
semantic-release-bot
f00a95c0d8 chore: Release v5.27.0-dev.3 [skip ci]
# [5.27.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.2...v5.27.0-dev.3) (2025-06-06)

### Bug Fixes

* **Spotify:** `Hide Create button` patch failing in edge cases ([#5131](https://github.com/ReVanced/revanced-patches/issues/5131)) ([7a432e5](7a432e5741))
2025-06-06 21:14:18 +00:00
Nuckyz
7a432e5741 fix(Spotify): Hide Create button patch failing in edge cases (#5131) 2025-06-06 18:11:32 -03:00
semantic-release-bot
966a78bd81 chore: Release v5.27.0-dev.2 [skip ci]
# [5.27.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.27.0-dev.1...v5.27.0-dev.2) (2025-06-06)

### Bug Fixes

* **YouTube - Video quality:** Remove non-functional Shorts 144p default quality ([6aff8e8](6aff8e8ca4))
2025-06-06 07:06:49 +00:00
LisoUseInAIKyrios
6aff8e8ca4 fix(YouTube - Video quality): Remove non-functional Shorts 144p default quality 2025-06-06 09:04:07 +02:00
github-actions[bot]
11aa463fa6 chore: Sync translations (#5125) 2025-06-06 09:03:38 +02:00
semantic-release-bot
bf1b639a2f chore: Release v5.27.0-dev.1 [skip ci]
# [5.27.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.26.1-dev.3...v5.27.0-dev.1) (2025-06-05)

### Features

* **YouTube - Theme:** Add option for black and white splash screen animation ([#5119](https://github.com/ReVanced/revanced-patches/issues/5119)) ([6d5380d](6d5380d44d))
2025-06-05 20:08:58 +00:00
LisoUseInAIKyrios
6d5380d44d feat(YouTube - Theme): Add option for black and white splash screen animation (#5119) 2025-06-05 22:06:12 +02:00
github-actions[bot]
7e1547b5b9 chore: Sync translations (#5123) 2025-06-05 22:05:56 +02:00
semantic-release-bot
c790b45cc5 chore: Release v5.26.1-dev.3 [skip ci]
## [5.26.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.26.1-dev.2...v5.26.1-dev.3) (2025-06-05)

### Bug Fixes

* **Spotify:** Prevent hiding all navigation bar buttons ([#5122](https://github.com/ReVanced/revanced-patches/issues/5122)) ([65fc6b4](65fc6b43f5))
2025-06-05 19:57:52 +00:00
Nuckyz
65fc6b43f5 fix(Spotify): Prevent hiding all navigation bar buttons (#5122) 2025-06-05 16:55:33 -03:00
semantic-release-bot
2257dd90aa chore: Release v5.26.1-dev.2 [skip ci]
## [5.26.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.26.1-dev.1...v5.26.1-dev.2) (2025-06-05)

### Bug Fixes

* **YouTube - Hide layout components:** Remove broken option 'Hide comments emoji picker' ([#5121](https://github.com/ReVanced/revanced-patches/issues/5121)) ([4b8499f](4b8499ff2c))
2025-06-05 19:12:08 +00:00
LisoUseInAIKyrios
4b8499ff2c fix(YouTube - Hide layout components): Remove broken option 'Hide comments emoji picker' (#5121) 2025-06-05 21:09:25 +02:00
Nuckyz
bde3fda972 refactor(Spotify): Add extensions debug logging (#5110) 2025-06-05 16:04:02 -03:00
semantic-release-bot
e2e07b5cb2 chore: Release v5.26.1-dev.1 [skip ci]
## [5.26.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.26.0...v5.26.1-dev.1) (2025-06-05)

### Bug Fixes

* **YouTube - Hide Shorts components:** Disable A/B player flags that prevents hiding buttons ([9d10ab6](9d10ab6c00))
2025-06-05 09:24:29 +00:00
LisoUseInAIKyrios
9d10ab6c00 fix(YouTube - Hide Shorts components): Disable A/B player flags that prevents hiding buttons 2025-06-05 11:21:05 +02:00
github-actions[bot]
d7644152fd chore: Sync translations (#5116) 2025-06-05 11:19:38 +02:00
LisoUseInAIKyrios
9be21f4824 refactor(YouTube - Hide Shorts components): Rename 'Hide comment panel' to 'Hide preview comment' 2025-06-05 11:08:24 +02:00
semantic-release-bot
a2eae0bf04 chore: Release v5.26.0 [skip ci]
# [5.26.0](https://github.com/ReVanced/revanced-patches/compare/v5.25.0...v5.26.0) (2025-06-04)

### Bug Fixes

* **Spotify - Custom theme:** Apply accent color in more places ([#5039](https://github.com/ReVanced/revanced-patches/issues/5039)) ([bc45433](bc45433dcb))
* **YouTube - Hide Shorts components:** Disable A/B player that prevents hiding buttons ([#5104](https://github.com/ReVanced/revanced-patches/issues/5104)) ([1d0c568](1d0c56819b))
* **YouTube:** Support A/B Shorts layout for RYD and component hiding ([#5081](https://github.com/ReVanced/revanced-patches/issues/5081)) ([ff903ba](ff903ba9ac))

### Features

* **Proton Mail:** Add `Remove free accounts limit` patch ([#4970](https://github.com/ReVanced/revanced-patches/issues/4970)) ([49ae0df](49ae0df224))
* **Spotify:** Add `Hide Create button` patch ([#5062](https://github.com/ReVanced/revanced-patches/issues/5062)) ([ce5385b](ce5385b28e))
* **Sync for Reddit:** Add `Fix post thumbnails` patch ([7a53580](7a53580380))
* **YouTube - Hide Shorts components:** Add option to hide comment panel ([#5102](https://github.com/ReVanced/revanced-patches/issues/5102)) ([e435b33](e435b33593))
* **YouTube - Playback Speed:** Use modern custom speed dialog ([#5069](https://github.com/ReVanced/revanced-patches/issues/5069)) ([a320e35](a320e35c32))
2025-06-04 14:05:56 +00:00
LisoUseInAIKyrios
679354b5b3 chore: Merge branch dev to main (#5079) 2025-06-04 16:02:42 +02:00
semantic-release-bot
91dec21033 chore: Release v5.26.0-dev.8 [skip ci]
# [5.26.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.7...v5.26.0-dev.8) (2025-06-04)

### Bug Fixes

* **YouTube - Hide Shorts components:** Disable A/B player that prevents hiding buttons ([#5104](https://github.com/ReVanced/revanced-patches/issues/5104)) ([1d0c568](1d0c56819b))
2025-06-04 11:48:26 +00:00
LisoUseInAIKyrios
1d0c56819b fix(YouTube - Hide Shorts components): Disable A/B player that prevents hiding buttons (#5104) 2025-06-04 13:45:48 +02:00
github-actions[bot]
4410816c22 chore: Sync translations (#5106) 2025-06-04 13:44:35 +02:00
semantic-release-bot
7e4e48bc9f chore: Release v5.26.0-dev.7 [skip ci]
# [5.26.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.6...v5.26.0-dev.7) (2025-06-04)

### Features

* **YouTube - Hide Shorts components:** Add option to hide comment panel ([#5102](https://github.com/ReVanced/revanced-patches/issues/5102)) ([e435b33](e435b33593))
2025-06-04 07:09:39 +00:00
LisoUseInAIKyrios
e435b33593 feat(YouTube - Hide Shorts components): Add option to hide comment panel (#5102) 2025-06-04 09:06:27 +02:00
semantic-release-bot
bf288b83ae chore: Release v5.26.0-dev.6 [skip ci]
# [5.26.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.5...v5.26.0-dev.6) (2025-06-03)

### Features

* **Sync for Reddit:** Add `Fix post thumbnails` patch ([7a53580](7a53580380))
2025-06-03 19:50:57 +00:00
kolpazar
7a53580380 feat(Sync for Reddit): Add Fix post thumbnails patch 2025-06-03 21:48:24 +02:00
semantic-release-bot
6439efa2a9 chore: Release v5.26.0-dev.5 [skip ci]
# [5.26.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.4...v5.26.0-dev.5) (2025-06-03)

### Bug Fixes

* **Spotify - Custom theme:** Apply accent color in more places ([#5039](https://github.com/ReVanced/revanced-patches/issues/5039)) ([bc45433](bc45433dcb))
2025-06-03 08:04:58 +00:00
Cilly Leang
bc45433dcb fix(Spotify - Custom theme): Apply accent color in more places (#5039)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-06-03 10:02:15 +02:00
github-actions[bot]
8871803e83 chore: Sync translations (#5095) 2025-06-03 09:59:31 +02:00
semantic-release-bot
18954a0285 chore: Release v5.26.0-dev.4 [skip ci]
# [5.26.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.3...v5.26.0-dev.4) (2025-06-03)

### Features

* **Spotify:** Add `Hide Create button` patch ([#5062](https://github.com/ReVanced/revanced-patches/issues/5062)) ([ce5385b](ce5385b28e))
2025-06-03 07:18:30 +00:00
Nuckyz
ce5385b28e feat(Spotify): Add Hide Create button patch (#5062) 2025-06-03 09:15:52 +02:00
dependabot[bot]
3f4cdf6f83 chore(deps-dev): bump semantic-release from 24.2.1 to 24.2.5 (#5086) 2025-06-01 20:57:25 +02:00
semantic-release-bot
094b4a1ea8 chore: Release v5.26.0-dev.3 [skip ci]
# [5.26.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.2...v5.26.0-dev.3) (2025-06-01)

### Features

* **YouTube - Playback Speed:** Use modern custom speed dialog ([#5069](https://github.com/ReVanced/revanced-patches/issues/5069)) ([a320e35](a320e35c32))
2025-06-01 09:15:51 +00:00
MarcaD
a320e35c32 feat(YouTube - Playback Speed): Use modern custom speed dialog (#5069)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-06-01 11:12:56 +02:00
semantic-release-bot
5bf5a2d2db chore: Release v5.26.0-dev.2 [skip ci]
# [5.26.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.26.0-dev.1...v5.26.0-dev.2) (2025-06-01)

### Bug Fixes

* **YouTube:** Support A/B Shorts layout for RYD and component hiding ([#5081](https://github.com/ReVanced/revanced-patches/issues/5081)) ([ff903ba](ff903ba9ac))
2025-06-01 07:01:35 +00:00
alieRN
ff903ba9ac fix(YouTube): Support A/B Shorts layout for RYD and component hiding (#5081) 2025-06-01 08:59:09 +02:00
github-actions[bot]
1079a54dbe chore: Sync translations (#5084) 2025-06-01 08:58:37 +02:00
ILoveOpenSourceApplications
2b0e3b4553 refactor: Make strings consistent (#5075) 2025-05-31 10:25:04 +02:00
semantic-release-bot
0265a7791b chore: Release v5.26.0-dev.1 [skip ci]
# [5.26.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.25.0...v5.26.0-dev.1) (2025-05-30)

### Features

* **Proton Mail:** Add `Remove free accounts limit` patch ([#4970](https://github.com/ReVanced/revanced-patches/issues/4970)) ([49ae0df](49ae0df224))
2025-05-30 20:53:45 +00:00
ByteEVM
49ae0df224 feat(Proton Mail): Add Remove free accounts limit patch (#4970)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-05-30 22:51:12 +02:00
semantic-release-bot
e279491724 chore: Release v5.25.0 [skip ci]
# [5.25.0](https://github.com/ReVanced/revanced-patches/compare/v5.24.0...v5.25.0) (2025-05-29)

### Bug Fixes

* **Disable Pairip license check:** Change patch to default off ([798596f](798596fd83))
* **Hide ADB status:** Resolve app crash on startup ([#5029](https://github.com/ReVanced/revanced-patches/issues/5029)) ([2984d73](2984d7362d))
* **Messenger:** Remove outdated `Disable switching emoji to sticker` patch ([#5044](https://github.com/ReVanced/revanced-patches/issues/5044)) ([517368e](517368eda7))
* **Spotify Lite:** Remove obsolete `Enable on demand` patch ([#5046](https://github.com/ReVanced/revanced-patches/issues/5046)) ([b712f38](b712f38017))
* **YouTube - GmsCore support:** Restore patch functionality from prior merge ([b6047fa](b6047fa6b3))
* **YouTube - Hide ads:** Hide new type of general ad ([#5004](https://github.com/ReVanced/revanced-patches/issues/5004)) ([bc0c3c4](bc0c3c452d))
* **YouTube - Open Shorts in regular player:** Do not exit app when pressing back button in regular player ([#5020](https://github.com/ReVanced/revanced-patches/issues/5020)) ([4ab1f0c](4ab1f0cfa9))
* **YouTube:** Better handle incorrect duplicate translations ([8d61ba9](8d61ba90c3))
* **Yuka - Unlock premium:** Remove broken patch that is no longer supported ([#5018](https://github.com/ReVanced/revanced-patches/issues/5018)) ([e286dab](e286dab74e))

### Features

* Add `Disable pairip license check` patch ([#4927](https://github.com/ReVanced/revanced-patches/issues/4927)) ([dea7108](dea7108c45))
* **Messenger:** Add `Remove Meta AI` patch ([#4945](https://github.com/ReVanced/revanced-patches/issues/4945)) ([52b9dc5](52b9dc5c9f))
* **Prime Video:** Add `Rename shared permissions` patch ([#5049](https://github.com/ReVanced/revanced-patches/issues/5049)) ([02373b0](02373b0bd2))
* **Spotify:** Add `Fix Facebook login` patch ([#5023](https://github.com/ReVanced/revanced-patches/issues/5023)) ([795016a](795016abce))
* **Threads:** Hide Ads ([#5064](https://github.com/ReVanced/revanced-patches/issues/5064)) ([bf1f26d](bf1f26d8bb))
* **YouTube - Enable debugging:** Add settings menu to share debug logs ([#5021](https://github.com/ReVanced/revanced-patches/issues/5021)) ([83c148a](83c148addc))
* **YouTube - Settings:** Add a color picker ([#4981](https://github.com/ReVanced/revanced-patches/issues/4981)) ([584b00f](584b00fd87))
* **YouTube - Swipe controls:** Add separate color settings for the brightness and volume bars ([#5043](https://github.com/ReVanced/revanced-patches/issues/5043)) ([443b54b](443b54bf09))
* **YouTube:** Add `Disable haptic feedback` patch ([#5033](https://github.com/ReVanced/revanced-patches/issues/5033)) ([5c8ed05](5c8ed05727))
2025-05-29 07:26:20 +00:00
LisoUseInAIKyrios
495260fe2b chore: Merge branch dev to main (#5010) 2025-05-29 09:22:53 +02:00
github-actions[bot]
40f069fff7 chore: Sync translations (#5066) 2025-05-29 09:20:59 +02:00
semantic-release-bot
de263c1061 chore: Release v5.25.0-dev.14 [skip ci]
# [5.25.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.13...v5.25.0-dev.14) (2025-05-29)

### Features

* **Threads:** Hide Ads ([#5064](https://github.com/ReVanced/revanced-patches/issues/5064)) ([bf1f26d](bf1f26d8bb))
2025-05-29 07:17:42 +00:00
scruz
bf1f26d8bb feat(Threads): Hide Ads (#5064) 2025-05-29 09:14:24 +02:00
semantic-release-bot
0ee2ed72d4 chore: Release v5.25.0-dev.13 [skip ci]
# [5.25.0-dev.13](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.12...v5.25.0-dev.13) (2025-05-28)

### Features

* **Prime Video:** Add `Rename shared permissions` patch ([#5049](https://github.com/ReVanced/revanced-patches/issues/5049)) ([02373b0](02373b0bd2))
2025-05-28 20:41:45 +00:00
hoodles
02373b0bd2 feat(Prime Video): Add Rename shared permissions patch (#5049) 2025-05-28 22:38:09 +02:00
github-actions[bot]
97c8e2489d chore: Sync translations (#5061) 2025-05-28 22:37:18 +02:00
semantic-release-bot
08b2b2e104 chore: Release v5.25.0-dev.12 [skip ci]
# [5.25.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.11...v5.25.0-dev.12) (2025-05-28)

### Features

* **YouTube - Swipe controls:** Add separate color settings for the brightness and volume bars ([#5043](https://github.com/ReVanced/revanced-patches/issues/5043)) ([443b54b](443b54bf09))
2025-05-28 10:02:34 +00:00
github-actions[bot]
6b386b67d2 chore: Sync translations (#5055) 2025-05-28 11:58:56 +02:00
Nuckyz
f8343ae9f6 refactor(Spotify): Improve protobuf array list mutability patch (#5053)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-05-28 11:55:25 +02:00
LisoUseInAIKyrios
3ba791ac7d refactor(YouTube - Enabling debugging): Adjust logger formatting to preserve backwards compatibility (#5054) 2025-05-28 11:55:02 +02:00
MarcaD
443b54bf09 feat(YouTube - Swipe controls): Add separate color settings for the brightness and volume bars (#5043) 2025-05-28 11:54:28 +02:00
semantic-release-bot
53587f190d chore: Release v5.25.0-dev.11 [skip ci]
# [5.25.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.10...v5.25.0-dev.11) (2025-05-27)

### Features

* **YouTube - Enable debugging:** Add settings menu to share debug logs ([#5021](https://github.com/ReVanced/revanced-patches/issues/5021)) ([83c148a](83c148addc))
* **YouTube:** Add `Disable haptic feedback` patch ([#5033](https://github.com/ReVanced/revanced-patches/issues/5033)) ([5c8ed05](5c8ed05727))
2025-05-27 07:55:39 +00:00
MarcaD
83c148addc feat(YouTube - Enable debugging): Add settings menu to share debug logs (#5021)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-05-27 09:52:24 +02:00
MarcaD
5c8ed05727 feat(YouTube): Add Disable haptic feedback patch (#5033) 2025-05-27 09:52:01 +02:00
semantic-release-bot
33833d7a1e chore: Release v5.25.0-dev.10 [skip ci]
# [5.25.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.9...v5.25.0-dev.10) (2025-05-27)

### Bug Fixes

* **Messenger:** Remove outdated `Disable switching emoji to sticker` patch ([#5044](https://github.com/ReVanced/revanced-patches/issues/5044)) ([517368e](517368eda7))
* **Spotify Lite:** Remove obsolete `Enable on demand` patch ([#5046](https://github.com/ReVanced/revanced-patches/issues/5046)) ([b712f38](b712f38017))
2025-05-27 06:51:05 +00:00
LisoUseInAIKyrios
b712f38017 fix(Spotify Lite): Remove obsolete Enable on demand patch (#5046) 2025-05-27 08:47:56 +02:00
LisoUseInAIKyrios
517368eda7 fix(Messenger): Remove outdated Disable switching emoji to sticker patch (#5044) 2025-05-27 08:47:09 +02:00
LisoUseInAIKyrios
2093c0c175 chore: fix api dump 2025-05-26 12:36:16 +02:00
semantic-release-bot
a7cfd80bfe chore: Release v5.25.0-dev.9 [skip ci]
# [5.25.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.8...v5.25.0-dev.9) (2025-05-26)

### Features

* **Spotify:** Add `Fix Facebook login` patch ([#5023](https://github.com/ReVanced/revanced-patches/issues/5023)) ([795016a](795016abce))
* **YouTube - Settings:** Add a color picker ([#4981](https://github.com/ReVanced/revanced-patches/issues/4981)) ([584b00f](584b00fd87))
2025-05-26 09:48:51 +00:00
github-actions[bot]
2990dc6d4e chore: Sync translations (#5038) 2025-05-26 10:39:02 +02:00
semantic-release-bot
c0e52bb6b3 chore: Release v5.25.0-dev.9 [skip ci]
# [5.25.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.8...v5.25.0-dev.9) (2025-05-26)

### Features

* **Spotify:** Add `Fix Facebook login` patch ([#5023](https://github.com/ReVanced/revanced-patches/issues/5023)) ([795016a](795016abce))
* **YouTube - Settings:** Add a color picker ([#4981](https://github.com/ReVanced/revanced-patches/issues/4981)) ([584b00f](584b00fd87))
2025-05-26 07:53:26 +00:00
github-actions[bot]
93fdd6f538 chore: Sync translations (#5037) 2025-05-26 09:49:50 +02:00
semantic-release-bot
decd249f20 chore: Release v5.25.0-dev.9 [skip ci]
# [5.25.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.8...v5.25.0-dev.9) (2025-05-26)

### Features

* **Spotify:** Add `Fix Facebook login` patch ([#5023](https://github.com/ReVanced/revanced-patches/issues/5023)) ([795016a](795016abce))
* **YouTube - Settings:** Add a color picker ([#4981](https://github.com/ReVanced/revanced-patches/issues/4981)) ([584b00f](584b00fd87))
2025-05-26 07:29:23 +00:00
github-actions[bot]
d79cb3eea8 chore: Sync translations (#5036) 2025-05-26 09:25:54 +02:00
MarcaD
584b00fd87 feat(YouTube - Settings): Add a color picker (#4981)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-05-26 09:08:45 +02:00
Nuckyz
795016abce feat(Spotify): Add Fix Facebook login patch (#5023) 2025-05-26 09:08:15 +02:00
semantic-release-bot
dc1dbd50a8 chore: Release v5.25.0-dev.8 [skip ci]
# [5.25.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.7...v5.25.0-dev.8) (2025-05-25)

### Bug Fixes

* **Hide ADB status:** Resolve app crash on startup ([#5029](https://github.com/ReVanced/revanced-patches/issues/5029)) ([2984d73](2984d7362d))
2025-05-25 17:41:52 +00:00
1fexd
2984d7362d fix(Hide ADB status): Resolve app crash on startup (#5029) 2025-05-25 19:38:19 +02:00
semantic-release-bot
627aed4010 chore: Release v5.25.0-dev.7 [skip ci]
# [5.25.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.6...v5.25.0-dev.7) (2025-05-24)

### Bug Fixes

* **YouTube - Open Shorts in regular player:** Do not exit app when pressing back button in regular player ([#5020](https://github.com/ReVanced/revanced-patches/issues/5020)) ([4ab1f0c](4ab1f0cfa9))
2025-05-24 11:16:03 +00:00
LisoUseInAIKyrios
4ab1f0cfa9 fix(YouTube - Open Shorts in regular player): Do not exit app when pressing back button in regular player (#5020) 2025-05-24 13:12:39 +02:00
semantic-release-bot
86e8e61ab2 chore: Release v5.25.0-dev.6 [skip ci]
# [5.25.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.5...v5.25.0-dev.6) (2025-05-23)

### Bug Fixes

* **Yuka - Unlock premium:** Remove broken patch that is no longer supported ([#5018](https://github.com/ReVanced/revanced-patches/issues/5018)) ([e286dab](e286dab74e))
2025-05-23 19:58:47 +00:00
LisoUseInAIKyrios
e286dab74e fix(Yuka - Unlock premium): Remove broken patch that is no longer supported (#5018) 2025-05-23 21:55:04 +02:00
github-actions[bot]
712a82439f chore: Sync translations (#5019) 2025-05-23 21:54:47 +02:00
semantic-release-bot
4449546c85 chore: Release v5.25.0-dev.5 [skip ci]
# [5.25.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.4...v5.25.0-dev.5) (2025-05-22)

### Bug Fixes

* **YouTube:** Better handle incorrect duplicate translations ([8d61ba9](8d61ba90c3))
2025-05-22 19:23:25 +00:00
LisoUseInAIKyrios
8d61ba90c3 fix(YouTube): Better handle incorrect duplicate translations 2025-05-22 21:20:01 +02:00
semantic-release-bot
689be79f71 chore: Release v5.25.0-dev.4 [skip ci]
# [5.25.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.3...v5.25.0-dev.4) (2025-05-22)

### Bug Fixes

* **YouTube - GmsCore support:** Restore patch functionality from prior merge ([b6047fa](b6047fa6b3))
2025-05-22 17:28:53 +00:00
LisoUseInAIKyrios
b6047fa6b3 fix(YouTube - GmsCore support): Restore patch functionality from prior merge 2025-05-22 19:25:15 +02:00
semantic-release-bot
82bbd603ac chore: Release v5.25.0-dev.3 [skip ci]
# [5.25.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.2...v5.25.0-dev.3) (2025-05-22)

### Bug Fixes

* **YouTube - Hide ads:** Hide new type of general ad ([#5004](https://github.com/ReVanced/revanced-patches/issues/5004)) ([bc0c3c4](bc0c3c452d))
2025-05-22 16:38:22 +00:00
ILoveOpenSourceApplications
bc0c3c452d fix(YouTube - Hide ads): Hide new type of general ad (#5004) 2025-05-22 18:35:11 +02:00
Pun Butrach
fe864d8331 ci: Attest release artifacts (#4816)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-05-22 14:56:33 +02:00
semantic-release-bot
4f686935c3 chore: Release v5.25.0-dev.2 [skip ci]
# [5.25.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.25.0-dev.1...v5.25.0-dev.2) (2025-05-22)

### Bug Fixes

* **Disable Pairip license check:** Change patch to default off ([798596f](798596fd83))
2025-05-22 10:18:30 +00:00
LisoUseInAIKyrios
798596fd83 fix(Disable Pairip license check): Change patch to default off 2025-05-22 12:14:33 +02:00
semantic-release-bot
38b37f182a chore: Release v5.25.0-dev.1 [skip ci]
# [5.25.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.24.0...v5.25.0-dev.1) (2025-05-22)

### Features

* Add `Disable pairip license check` patch ([#4927](https://github.com/ReVanced/revanced-patches/issues/4927)) ([dea7108](dea7108c45))
* **Messenger:** Add `Remove Meta AI` patch ([#4945](https://github.com/ReVanced/revanced-patches/issues/4945)) ([52b9dc5](52b9dc5c9f))
2025-05-22 08:39:21 +00:00
Dawid Krajcarz
52b9dc5c9f feat(Messenger): Add Remove Meta AI patch (#4945) 2025-05-22 10:35:31 +02:00
hoodles
dea7108c45 feat: Add Disable pairip license check patch (#4927)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-05-22 10:35:16 +02:00
github-actions[bot]
24b4579cb9 chore: Sync translations (#5009) 2025-05-22 10:33:36 +02:00
semantic-release-bot
0b52f3d192 chore: Release v5.24.0 [skip ci]
# [5.24.0](https://github.com/ReVanced/revanced-patches/compare/v5.23.0...v5.24.0) (2025-05-19)

### Bug Fixes

* **Spotify - Fix third party launchers widgets:** Add missing compatibility annotation ([e68cd70](e68cd70f66))
* **YouTube - Hide layout components:** Fix `Hide video recommendation labels` ([#4956](https://github.com/ReVanced/revanced-patches/issues/4956)) ([9aec199](9aec1999bb))
* **YouTube - Settings:** Correctly show summary text if search box is closed before searching ([e59c9e9](e59c9e9b3c))
* **YouTube - SponsorBlock:** Fix segment category summary not showing category description ([b2b09a2](b2b09a2025))

### Features

* **GmsCore support:** Open vendor specific DontKillMyApp if available ([#4952](https://github.com/ReVanced/revanced-patches/issues/4952)) ([d2b440d](d2b440d800))
* **NU.nl:** Support version `11.3.0` ([#4925](https://github.com/ReVanced/revanced-patches/issues/4925)) ([887c9f0](887c9f0d75))
* **Spotify:** Add `Fix third party launchers widgets` patch ([#4893](https://github.com/ReVanced/revanced-patches/issues/4893)) ([db68c41](db68c41d5e))
* **YouTube - Hide description components:** Add `Hide Ask` ([#4972](https://github.com/ReVanced/revanced-patches/issues/4972)) ([e582908](e58290839f))
* **YouTube - Hide layout components:** Add `Hide ticket shelf` ([#4969](https://github.com/ReVanced/revanced-patches/issues/4969)) ([4cd0ae9](4cd0ae9b92))
* **YouTube - Hide player components:** Hide related video overlay in fullscreen ([#4938](https://github.com/ReVanced/revanced-patches/issues/4938)) ([f454183](f454183646))
* **YouTube - Settings:** Add ability to search in settings ([#4881](https://github.com/ReVanced/revanced-patches/issues/4881)) ([14a8f4f](14a8f4fb96))
2025-05-19 10:32:36 +00:00
LisoUseInAIKyrios
18c374a81e chore: Merge branch dev to main (#4947) 2025-05-19 14:28:47 +04:00
github-actions[bot]
092303e431 chore: Sync translations (#4995) 2025-05-19 14:25:25 +04:00
semantic-release-bot
6bf5bf9d45 chore: Release v5.24.0-dev.9 [skip ci]
# [5.24.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.8...v5.24.0-dev.9) (2025-05-18)

### Bug Fixes

* **YouTube - SponsorBlock:** Fix segment category summary not showing category description ([b2b09a2](b2b09a2025))
2025-05-18 08:29:10 +00:00
LisoUseInAIKyrios
b2b09a2025 fix(YouTube - SponsorBlock): Fix segment category summary not showing category description 2025-05-18 12:25:43 +04:00
semantic-release-bot
4a3a7f1674 chore: Release v5.24.0-dev.8 [skip ci]
# [5.24.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.7...v5.24.0-dev.8) (2025-05-17)

### Bug Fixes

* **YouTube - Settings:** Correctly show summary text if search box is closed before searching ([e59c9e9](e59c9e9b3c))
2025-05-17 18:00:22 +00:00
LisoUseInAIKyrios
e59c9e9b3c fix(YouTube - Settings): Correctly show summary text if search box is closed before searching 2025-05-17 21:57:03 +04:00
github-actions[bot]
dfb552b01a chore: Sync translations (#4978) 2025-05-17 21:56:48 +04:00
github-actions[bot]
94999c56b1 chore: Sync translations (#4975) 2025-05-17 15:19:14 +04:00
semantic-release-bot
c4fd1f0146 chore: Release v5.24.0-dev.7 [skip ci]
# [5.24.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.6...v5.24.0-dev.7) (2025-05-17)

### Features

* **YouTube - Hide layout components:** Add `Hide ticket shelf` ([#4969](https://github.com/ReVanced/revanced-patches/issues/4969)) ([4cd0ae9](4cd0ae9b92))
2025-05-17 10:51:31 +00:00
ILoveOpenSourceApplications
4cd0ae9b92 feat(YouTube - Hide layout components): Add Hide ticket shelf (#4969) 2025-05-17 14:48:05 +04:00
github-actions[bot]
9548d581c1 chore: Sync translations (#4974) 2025-05-17 14:46:10 +04:00
LisoUseInAIKyrios
a2fe3af6be refactor(YouTube - Litho filter): Simplify debug logging code 2025-05-17 12:26:37 +04:00
semantic-release-bot
6ef6504d41 chore: Release v5.24.0-dev.6 [skip ci]
# [5.24.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.5...v5.24.0-dev.6) (2025-05-17)

### Features

* **YouTube - Hide description components:** Add `Hide Ask` ([#4972](https://github.com/ReVanced/revanced-patches/issues/4972)) ([e582908](e58290839f))
2025-05-17 07:56:03 +00:00
ILoveOpenSourceApplications
e58290839f feat(YouTube - Hide description components): Add Hide Ask (#4972) 2025-05-17 11:52:33 +04:00
github-actions[bot]
e18260bd65 chore: Sync translations (#4973) 2025-05-17 11:46:53 +04:00
semantic-release-bot
b2fcd5a846 chore: Release v5.24.0-dev.5 [skip ci]
# [5.24.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.4...v5.24.0-dev.5) (2025-05-17)

### Bug Fixes

* **Spotify - Fix third party launchers widgets:** Add missing compatibility annotation ([e68cd70](e68cd70f66))

### Features

* **YouTube - Settings:** Add ability to search in settings ([#4881](https://github.com/ReVanced/revanced-patches/issues/4881)) ([14a8f4f](14a8f4fb96))
2025-05-17 07:44:42 +00:00
LisoUseInAIKyrios
e68cd70f66 fix(Spotify - Fix third party launchers widgets): Add missing compatibility annotation 2025-05-17 11:40:37 +04:00
MarcaD
14a8f4fb96 feat(YouTube - Settings): Add ability to search in settings (#4881)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-05-17 11:40:16 +04:00
semantic-release-bot
2593c004f4 chore: Release v5.24.0-dev.4 [skip ci]
# [5.24.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.3...v5.24.0-dev.4) (2025-05-16)

### Features

* **Spotify:** Add `Fix third party launchers widgets` patch ([#4893](https://github.com/ReVanced/revanced-patches/issues/4893)) ([db68c41](db68c41d5e))
2025-05-16 17:18:15 +00:00
Nuckyz
db68c41d5e feat(Spotify): Add Fix third party launchers widgets patch (#4893)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-05-16 19:14:26 +02:00
semantic-release-bot
a4f9cb3cef chore: Release v5.24.0-dev.3 [skip ci]
# [5.24.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.2...v5.24.0-dev.3) (2025-05-14)

### Bug Fixes

* **YouTube - Hide layout components:** Fix `Hide video recommendation labels` ([#4956](https://github.com/ReVanced/revanced-patches/issues/4956)) ([9aec199](9aec1999bb))
2025-05-14 20:01:05 +00:00
ILoveOpenSourceApplications
9aec1999bb fix(YouTube - Hide layout components): Fix Hide video recommendation labels (#4956) 2025-05-14 23:57:47 +04:00
github-actions[bot]
26ecbe646e chore: Sync translations (#4960) 2025-05-14 23:57:11 +04:00
semantic-release-bot
46ba0d8a2e chore: Release v5.24.0-dev.2 [skip ci]
# [5.24.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.24.0-dev.1...v5.24.0-dev.2) (2025-05-14)

### Features

* **GmsCore support:** Open vendor specific DontKillMyApp if available ([#4952](https://github.com/ReVanced/revanced-patches/issues/4952)) ([d2b440d](d2b440d800))
* **YouTube - Hide player components:** Hide related video overlay in fullscreen ([#4938](https://github.com/ReVanced/revanced-patches/issues/4938)) ([f454183](f454183646))
2025-05-14 07:07:03 +00:00
MarcaD
f454183646 feat(YouTube - Hide player components): Hide related video overlay in fullscreen (#4938) 2025-05-14 11:03:33 +04:00
LisoUseInAIKyrios
d2b440d800 feat(GmsCore support): Open vendor specific DontKillMyApp if available (#4952) 2025-05-14 11:01:32 +04:00
hoodles
494c5f04a4 fix(Instagram) - Fix hide ads fingerprint and add bypass check signature (#4901)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-05-13 10:58:07 +04:00
semantic-release-bot
48d5fdf7e1 chore: Release v5.24.0-dev.1 [skip ci]
# [5.24.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.23.0...v5.24.0-dev.1) (2025-05-12)

### Features

* **NU.nl:** Support version `11.3.0` ([#4925](https://github.com/ReVanced/revanced-patches/issues/4925)) ([887c9f0](887c9f0d75))
2025-05-12 22:40:55 +00:00
Jasper Abbink
887c9f0d75 feat(NU.nl): Support version 11.3.0 (#4925) 2025-05-13 02:37:41 +04:00
github-actions[bot]
7de4c9d41d chore: Sync translations (#4946) 2025-05-13 02:36:53 +04:00
semantic-release-bot
7d3b8d9c42 chore: Release v5.23.0 [skip ci]
# [5.23.0](https://github.com/ReVanced/revanced-patches/compare/v5.22.0...v5.23.0) (2025-05-10)

### Bug Fixes

* Correct incorrect fingerprint ([5f05414](5f0541407c))
* Fix incorrect fingerprints ([#4917](https://github.com/ReVanced/revanced-patches/issues/4917)) ([796c118](796c118fe1))
* **Spotify - Unlock Spotify Premium:** Remove pop up premium ads ([#4842](https://github.com/ReVanced/revanced-patches/issues/4842)) ([5028c1a](5028c1acb3))
* **YouTube:** Improve litho filtering performance ([#4904](https://github.com/ReVanced/revanced-patches/issues/4904)) ([60fdf4c](60fdf4c44c))
* **YouTube:** Simplify litho filtering patch ([#4910](https://github.com/ReVanced/revanced-patches/issues/4910)) ([23fd720](23fd720fa7))

### Features

* **Lightroom:** Constrain patches to last working version ([858c59d](858c59d728))
* **Pandora:** Add `Disable audio ads` and `Unlimited skips` patch ([#4841](https://github.com/ReVanced/revanced-patches/issues/4841)) ([f4f36ff](f4f36ff273))
* **Prime Video:** Add `Skip ads` patch ([#4824](https://github.com/ReVanced/revanced-patches/issues/4824)) ([f8bdf74](f8bdf744ab))
* **Spotify:** Add `Sanitize sharing links` patch ([#4829](https://github.com/ReVanced/revanced-patches/issues/4829)) ([777957e](777957e2d0))
2025-05-10 09:02:41 +00:00
LisoUseInAIKyrios
25e1a965d6 chore: Merge branch dev to main (#4899) 2025-05-10 12:58:55 +04:00
github-actions[bot]
b29c01cee1 chore: Sync translations (#4933) 2025-05-10 12:39:30 +04:00
semantic-release-bot
639850471b chore: Release v5.23.0-dev.7 [skip ci]
# [5.23.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.23.0-dev.6...v5.23.0-dev.7) (2025-05-06)

### Bug Fixes

* Fix incorrect fingerprints ([#4917](https://github.com/ReVanced/revanced-patches/issues/4917)) ([796c118](796c118fe1))
2025-05-06 12:13:29 +00:00
Nuckyz
796c118fe1 fix: Fix incorrect fingerprints (#4917) 2025-05-06 16:09:54 +04:00
semantic-release-bot
edf20e397d chore: Release v5.23.0-dev.6 [skip ci]
# [5.23.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.23.0-dev.5...v5.23.0-dev.6) (2025-05-06)

### Bug Fixes

* Correct incorrect fingerprint ([5f05414](5f0541407c))
2025-05-06 10:50:54 +00:00
oSumAtrIX
5f0541407c fix: Correct incorrect fingerprint 2025-05-06 12:47:06 +02:00
semantic-release-bot
56b7ba9ba7 chore: Release v5.23.0-dev.5 [skip ci]
# [5.23.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.23.0-dev.4...v5.23.0-dev.5) (2025-05-06)

### Bug Fixes

* **Spotify - Unlock Spotify Premium:** Remove pop up premium ads ([#4842](https://github.com/ReVanced/revanced-patches/issues/4842)) ([5028c1a](5028c1acb3))

### Features

* **Pandora:** Add `Disable audio ads` and `Unlimited skips` patch ([#4841](https://github.com/ReVanced/revanced-patches/issues/4841)) ([f4f36ff](f4f36ff273))
* **Prime Video:** Add `Skip ads` patch ([#4824](https://github.com/ReVanced/revanced-patches/issues/4824)) ([f8bdf74](f8bdf744ab))
2025-05-06 07:44:30 +00:00
hoodles
f8bdf744ab feat(Prime Video): Add Skip ads patch (#4824) 2025-05-06 11:40:45 +04:00
hoodles
f4f36ff273 feat(Pandora): Add Disable audio ads and Unlimited skips patch (#4841)
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
2025-05-06 11:39:07 +04:00
Nuckyz
5028c1acb3 fix(Spotify - Unlock Spotify Premium): Remove pop up premium ads (#4842) 2025-05-06 11:35:47 +04:00
semantic-release-bot
555c9a5823 chore: Release v5.23.0-dev.4 [skip ci]
# [5.23.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.23.0-dev.3...v5.23.0-dev.4) (2025-05-06)

### Features

* **Spotify:** Add `Sanitize sharing links` patch ([#4829](https://github.com/ReVanced/revanced-patches/issues/4829)) ([777957e](777957e2d0))
2025-05-06 07:35:22 +00:00
Dawid Krajcarz
777957e2d0 feat(Spotify): Add Sanitize sharing links patch (#4829) 2025-05-06 11:31:56 +04:00
github-actions[bot]
b3316a5915 chore: Sync translations (#4915) 2025-05-06 11:31:12 +04:00
semantic-release-bot
2ca2bb7692 chore: Release v5.23.0-dev.3 [skip ci]
# [5.23.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.23.0-dev.2...v5.23.0-dev.3) (2025-05-05)

### Bug Fixes

* **YouTube:** Simplify litho filtering patch ([#4910](https://github.com/ReVanced/revanced-patches/issues/4910)) ([23fd720](23fd720fa7))
2025-05-05 11:28:44 +00:00
LisoUseInAIKyrios
23fd720fa7 fix(YouTube): Simplify litho filtering patch (#4910) 2025-05-05 15:25:25 +04:00
semantic-release-bot
1f08586ae8 chore: Release v5.23.0-dev.2 [skip ci]
# [5.23.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.23.0-dev.1...v5.23.0-dev.2) (2025-05-04)

### Bug Fixes

* **YouTube:** Improve litho filtering performance ([#4904](https://github.com/ReVanced/revanced-patches/issues/4904)) ([60fdf4c](60fdf4c44c))
2025-05-04 09:58:25 +00:00
LisoUseInAIKyrios
60fdf4c44c fix(YouTube): Improve litho filtering performance (#4904) 2025-05-04 13:55:12 +04:00
semantic-release-bot
63f3342815 chore: Release v5.23.0-dev.1 [skip ci]
# [5.23.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.22.0...v5.23.0-dev.1) (2025-05-02)

### Features

* **Lightroom:** Constrain patches to last working version ([858c59d](858c59d728))
2025-05-02 13:02:25 +00:00
oSumAtrIX
858c59d728 feat(Lightroom): Constrain patches to last working version 2025-05-02 14:58:57 +02:00
semantic-release-bot
5debf9936d chore: Release v5.22.0 [skip ci]
# [5.22.0](https://github.com/ReVanced/revanced-patches/compare/v5.21.0...v5.22.0) (2025-05-01)

### Bug Fixes

* **TikTok - Feed filter:** Hide ads in following feed ([#4844](https://github.com/ReVanced/revanced-patches/issues/4844)) ([b2453fe](b2453fecfc))
* **YouTube - Hide layout components:** Hide new type of community posts ([#4888](https://github.com/ReVanced/revanced-patches/issues/4888)) ([9b1013e](9b1013e1c2))
* **YouTube - Hide Shorts components:** Hide action buttons A/B button layout ([#4889](https://github.com/ReVanced/revanced-patches/issues/4889)) ([75d6cd7](75d6cd7c7b))
* **YouTube - Shorts autoplay:** Fix autoplay with YT 20.12 ([ef35ed7](ef35ed7335))
* **YouTube - Spoof app version:** Do not hide spoof version in general settings menu ([#4861](https://github.com/ReVanced/revanced-patches/issues/4861)) ([f69eab3](f69eab3e3b))

### Features

* **TikTok - Feed Filter:** Remove TikTok Shop from feed. ([#4851](https://github.com/ReVanced/revanced-patches/issues/4851)) ([72e0c01](72e0c01922))
* **YouTube - GmsCore support:** Show troubleshooting in app text if the user recently changed their account details ([#4879](https://github.com/ReVanced/revanced-patches/issues/4879)) ([45b5a51](45b5a51da3))
2025-05-01 07:03:38 +00:00
LisoUseInAIKyrios
f1b85d20a1 chore: Merge branch dev to main (#4864) 2025-05-01 11:00:16 +04:00
github-actions[bot]
37d0de5e93 chore: Sync translations (#4894) 2025-05-01 10:59:24 +04:00
semantic-release-bot
96d08d5eb7 chore: Release v5.22.0-dev.4 [skip ci]
# [5.22.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.22.0-dev.3...v5.22.0-dev.4) (2025-04-30)

### Bug Fixes

* **YouTube - Hide layout components:** Hide new type of community posts ([#4888](https://github.com/ReVanced/revanced-patches/issues/4888)) ([9b1013e](9b1013e1c2))
* **YouTube - Hide Shorts components:** Hide action buttons A/B button layout ([#4889](https://github.com/ReVanced/revanced-patches/issues/4889)) ([75d6cd7](75d6cd7c7b))
2025-04-30 22:11:17 +00:00
Bceez
9b1013e1c2 fix(YouTube - Hide layout components): Hide new type of community posts (#4888) 2025-05-01 02:07:52 +04:00
LisoUseInAIKyrios
75d6cd7c7b fix(YouTube - Hide Shorts components): Hide action buttons A/B button layout (#4889) 2025-05-01 02:07:32 +04:00
github-actions[bot]
5a17f5e1c1 chore: Sync translations (#4890) 2025-05-01 02:04:21 +04:00
MarcaD
1d16de6617 bug(YouTube - Theme): Fix white system navigation bar in the ReVanced settings (#4875) 2025-04-29 23:27:14 +04:00
github-actions[bot]
aee7cba46d chore: Sync translations (#4884) 2025-04-29 23:26:47 +04:00
semantic-release-bot
ec3faf30a8 chore: Release v5.22.0-dev.3 [skip ci]
# [5.22.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.22.0-dev.2...v5.22.0-dev.3) (2025-04-29)

### Features

* **YouTube - GmsCore support:** Show troubleshooting in app text if the user recently changed their account details ([#4879](https://github.com/ReVanced/revanced-patches/issues/4879)) ([45b5a51](45b5a51da3))
2025-04-29 09:40:18 +00:00
LisoUseInAIKyrios
45b5a51da3 feat(YouTube - GmsCore support): Show troubleshooting in app text if the user recently changed their account details (#4879) 2025-04-29 13:36:29 +04:00
semantic-release-bot
8abf176bc9 chore: Release v5.22.0-dev.2 [skip ci]
# [5.22.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.22.0-dev.1...v5.22.0-dev.2) (2025-04-27)

### Bug Fixes

* **YouTube - Shorts autoplay:** Fix autoplay with YT 20.12 ([ef35ed7](ef35ed7335))
2025-04-27 14:28:33 +00:00
LisoUseInAIKyrios
ef35ed7335 fix(YouTube - Shorts autoplay): Fix autoplay with YT 20.12 2025-04-27 18:24:37 +04:00
semantic-release-bot
4fd666b667 chore: Release v5.22.0-dev.1 [skip ci]
# [5.22.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.21.0...v5.22.0-dev.1) (2025-04-26)

### Bug Fixes

* **TikTok - Feed filter:** Hide ads in following feed ([#4844](https://github.com/ReVanced/revanced-patches/issues/4844)) ([b2453fe](b2453fecfc))
* **YouTube - Spoof app version:** Do not hide spoof version in general settings menu ([#4861](https://github.com/ReVanced/revanced-patches/issues/4861)) ([f69eab3](f69eab3e3b))

### Features

* **TikTok - Feed Filter:** Remove TikTok Shop from feed. ([#4851](https://github.com/ReVanced/revanced-patches/issues/4851)) ([72e0c01](72e0c01922))
2025-04-26 13:55:47 +00:00
3igcheeze
72e0c01922 feat(TikTok - Feed Filter): Remove TikTok Shop from feed. (#4851) 2025-04-26 17:52:17 +04:00
LisoUseInAIKyrios
f69eab3e3b fix(YouTube - Spoof app version): Do not hide spoof version in general settings menu (#4861) 2025-04-26 17:51:35 +04:00
github-actions[bot]
7c5c2d95bc chore: Sync translations (#4865) 2025-04-26 17:51:18 +04:00
Jaimy Smets
b2453fecfc fix(TikTok - Feed filter): Hide ads in following feed (#4844) 2025-04-26 17:49:28 +04:00
semantic-release-bot
0d54f8bd80 chore: Release v5.21.0 [skip ci]
# [5.21.0](https://github.com/ReVanced/revanced-patches/compare/v5.20.1...v5.21.0) (2025-04-25)

### Bug Fixes

* `Hide ADB status` patch ([#4814](https://github.com/ReVanced/revanced-patches/issues/4814)) ([5e069bd](5e069bde90))
* **GmsCore Support:** Correct the description to refer to the app being patched ([96512de](96512de6c9))
* **Wide search bar:** Fix patching `19.16.39` ([d7c9dd0](d7c9dd0f77))
* **YouTube - Change start page:** Add option to always override start page on app launch ([#4832](https://github.com/ReVanced/revanced-patches/issues/4832)) ([896de89](896de8910a))
* **YouTube - Disable auto captions:** Correctly hide captions with YT 20.12 ([8efbaae](8efbaae65c))
* **YouTube - Hide video action buttons:** Add option to hide 'Ask' button ([#4852](https://github.com/ReVanced/revanced-patches/issues/4852)) ([2d94ba9](2d94ba9df6))
* **YouTube - Hide video action buttons:** Hide A/B layout buttons ([15053e2](15053e2b68))
* **YouTube - Wide search bar:** Do not force phone layout for tablet devices ([#4827](https://github.com/ReVanced/revanced-patches/issues/4827)) ([77ea5c4](77ea5c4033))

### Features

* Add `Hide ADB status` patch ([#4585](https://github.com/ReVanced/revanced-patches/issues/4585)) ([7cc6995](7cc6995682))
* **X / Twitter:** Support version `10.86.0-release.0` ([#4805](https://github.com/ReVanced/revanced-patches/issues/4805)) ([fc6282d](fc6282d0cb))
* **YouTube - Swipe controls:** Add option for vertical progress bar ([#4811](https://github.com/ReVanced/revanced-patches/issues/4811)) ([6d69f01](6d69f01421))
* **YouTube:** Support version `20.12.46` ([#4779](https://github.com/ReVanced/revanced-patches/issues/4779)) ([f216e16](f216e16c0b))
2025-04-25 17:21:09 +00:00
LisoUseInAIKyrios
fda16fad1a chore: Merge branch dev to main (#4803) 2025-04-25 21:17:55 +04:00
github-actions[bot]
ddd43acd73 chore: Sync translations (#4858) 2025-04-25 21:17:12 +04:00
semantic-release-bot
3451318d53 chore: Release v5.21.0-dev.12 [skip ci]
# [5.21.0-dev.12](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.11...v5.21.0-dev.12) (2025-04-24)

### Bug Fixes

* **YouTube - Hide video action buttons:** Add option to hide 'Ask' button ([#4852](https://github.com/ReVanced/revanced-patches/issues/4852)) ([2d94ba9](2d94ba9df6))
2025-04-24 19:26:35 +00:00
LisoUseInAIKyrios
2d94ba9df6 fix(YouTube - Hide video action buttons): Add option to hide 'Ask' button (#4852) 2025-04-24 23:23:10 +04:00
github-actions[bot]
aaf3437a5a chore: Sync translations (#4853) 2025-04-24 23:21:29 +04:00
semantic-release-bot
ec8bf06047 chore: Release v5.21.0-dev.11 [skip ci]
# [5.21.0-dev.11](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.10...v5.21.0-dev.11) (2025-04-24)

### Bug Fixes

* **GmsCore Support:** Correct the description to refer to the app being patched ([96512de](96512de6c9))
2025-04-24 18:51:43 +00:00
oSumAtrIX
96512de6c9 fix(GmsCore Support): Correct the description to refer to the app being patched 2025-04-24 20:48:12 +02:00
semantic-release-bot
6114807c43 chore: Release v5.21.0-dev.10 [skip ci]
# [5.21.0-dev.10](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.9...v5.21.0-dev.10) (2025-04-23)

### Features

* **YouTube - Swipe controls:** Add option for vertical progress bar ([#4811](https://github.com/ReVanced/revanced-patches/issues/4811)) ([6d69f01](6d69f01421))
2025-04-23 11:34:08 +00:00
MarcaD
6d69f01421 feat(YouTube - Swipe controls): Add option for vertical progress bar (#4811) 2025-04-23 15:30:41 +04:00
github-actions[bot]
fd4218154d chore: Sync translations (#4845) 2025-04-23 15:30:22 +04:00
github-actions[bot]
8bed8a6622 chore: Sync translations (#4839) 2025-04-21 22:17:26 +02:00
semantic-release-bot
3174047223 chore: Release v5.21.0-dev.9 [skip ci]
# [5.21.0-dev.9](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.8...v5.21.0-dev.9) (2025-04-21)

### Bug Fixes

* **YouTube - Hide video action buttons:** Hide A/B layout buttons ([15053e2](15053e2b68))
2025-04-21 20:16:36 +00:00
LisoUseInAIKyrios
15053e2b68 fix(YouTube - Hide video action buttons): Hide A/B layout buttons 2025-04-21 22:13:04 +02:00
semantic-release-bot
e5b6aac018 chore: Release v5.21.0-dev.8 [skip ci]
# [5.21.0-dev.8](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.7...v5.21.0-dev.8) (2025-04-20)

### Bug Fixes

* **Wide search bar:** Fix patching `19.16.39` ([d7c9dd0](d7c9dd0f77))
2025-04-20 11:31:26 +00:00
LisoUseInAIKyrios
d7c9dd0f77 fix(Wide search bar): Fix patching 19.16.39 2025-04-20 13:27:55 +02:00
github-actions[bot]
a0eb6d5fdb chore: Sync translations (#4833) 2025-04-20 13:27:33 +02:00
semantic-release-bot
55c5eb3d14 chore: Release v5.21.0-dev.7 [skip ci]
# [5.21.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.6...v5.21.0-dev.7) (2025-04-20)

### Bug Fixes

* **YouTube - Change start page:** Add option to always override start page on app launch ([#4832](https://github.com/ReVanced/revanced-patches/issues/4832)) ([896de89](896de8910a))
2025-04-20 08:24:42 +00:00
LisoUseInAIKyrios
896de8910a fix(YouTube - Change start page): Add option to always override start page on app launch (#4832) 2025-04-20 10:21:03 +02:00
semantic-release-bot
e2a7e25c66 chore: Release v5.21.0-dev.6 [skip ci]
# [5.21.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.5...v5.21.0-dev.6) (2025-04-19)

### Bug Fixes

* **YouTube - Wide search bar:** Do not force phone layout for tablet devices ([#4827](https://github.com/ReVanced/revanced-patches/issues/4827)) ([77ea5c4](77ea5c4033))
2025-04-19 16:36:29 +00:00
LisoUseInAIKyrios
77ea5c4033 fix(YouTube - Wide search bar): Do not force phone layout for tablet devices (#4827) 2025-04-19 18:33:12 +02:00
github-actions[bot]
6eea2354f5 chore: Sync translations (#4828) 2025-04-19 12:00:28 +02:00
semantic-release-bot
cce21c4d4a chore: Release v5.21.0-dev.5 [skip ci]
# [5.21.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.4...v5.21.0-dev.5) (2025-04-18)

### Bug Fixes

* `Hide ADB status` patch ([#4814](https://github.com/ReVanced/revanced-patches/issues/4814)) ([5e069bd](5e069bde90))
2025-04-18 09:18:56 +00:00
1fexd
5e069bde90 fix: Hide ADB status patch (#4814) 2025-04-18 11:15:05 +02:00
github-actions[bot]
6a49208982 chore: Sync translations (#4822) 2025-04-18 09:55:15 +02:00
Snow
404bb2e86e chore(YouTube - Return YouTube Dislike): Clarify settings text for estimated likes (#4818) 2025-04-17 19:10:37 +02:00
github-actions[bot]
bc869fe359 chore: Sync translations (#4820) 2025-04-17 19:09:35 +02:00
semantic-release-bot
7d166cf82c chore: Release v5.21.0-dev.4 [skip ci]
# [5.21.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.3...v5.21.0-dev.4) (2025-04-17)

### Bug Fixes

* **YouTube - Disable auto captions:** Correctly hide captions with YT 20.12 ([8efbaae](8efbaae65c))
2025-04-17 17:06:19 +00:00
LisoUseInAIKyrios
8efbaae65c fix(YouTube - Disable auto captions): Correctly hide captions with YT 20.12 2025-04-17 19:02:52 +02:00
LisoUseInAIKyrios
e27ab23279 chore(YouTube): Add debug text to toast text if user forgot they enabled debugging 2025-04-16 14:56:31 +02:00
semantic-release-bot
ce42604083 chore: Release v5.21.0-dev.3 [skip ci]
# [5.21.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.2...v5.21.0-dev.3) (2025-04-16)

### Features

* **X / Twitter:** Support version `10.86.0-release.0` ([#4805](https://github.com/ReVanced/revanced-patches/issues/4805)) ([fc6282d](fc6282d0cb))
2025-04-16 11:09:43 +00:00
cyberboh
fc6282d0cb feat(X / Twitter): Support version 10.86.0-release.0 (#4805) 2025-04-16 13:06:30 +02:00
semantic-release-bot
0559fc7fd0 chore: Release v5.21.0-dev.2 [skip ci]
# [5.21.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.21.0-dev.1...v5.21.0-dev.2) (2025-04-16)

### Features

* Add `Hide ADB status` patch ([#4585](https://github.com/ReVanced/revanced-patches/issues/4585)) ([7cc6995](7cc6995682))
2025-04-16 08:58:30 +00:00
1fexd
7cc6995682 feat: Add Hide ADB status patch (#4585)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-04-16 10:55:07 +02:00
semantic-release-bot
476f13bf98 chore: Release v5.21.0-dev.1 [skip ci]
# [5.21.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.20.1...v5.21.0-dev.1) (2025-04-16)

### Features

* **YouTube:** Support version `20.12.46` ([#4779](https://github.com/ReVanced/revanced-patches/issues/4779)) ([f216e16](f216e16c0b))
2025-04-16 08:28:15 +00:00
LisoUseInAIKyrios
f216e16c0b feat(YouTube): Support version 20.12.46 (#4779) 2025-04-16 10:24:35 +02:00
semantic-release-bot
f2a8789649 chore: Release v5.20.1 [skip ci]
## [5.20.1](https://github.com/ReVanced/revanced-patches/compare/v5.20.0...v5.20.1) (2025-04-15)

### Bug Fixes

* **Spotify - Custom theme:** Support latest app target ([#4800](https://github.com/ReVanced/revanced-patches/issues/4800)) ([2393d0a](2393d0a8f5))
2025-04-15 16:41:52 +00:00
LisoUseInAIKyrios
5973b64f52 chore: Merge branch dev to main (#4801) 2025-04-15 18:38:29 +02:00
semantic-release-bot
102036706e chore: Release v5.20.1-dev.1 [skip ci]
## [5.20.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.20.0...v5.20.1-dev.1) (2025-04-15)

### Bug Fixes

* **Spotify - Custom theme:** Support latest app target ([#4800](https://github.com/ReVanced/revanced-patches/issues/4800)) ([2393d0a](2393d0a8f5))
2025-04-15 16:34:50 +00:00
LisoUseInAIKyrios
2393d0a8f5 fix(Spotify - Custom theme): Support latest app target (#4800) 2025-04-15 18:30:55 +02:00
LisoUseInAIKyrios
aea29b9522 refactor(Spotify - Spoof package info): Replace installer package name of legacy target (#4797) 2025-04-15 17:38:47 +02:00
semantic-release-bot
4db8ef7079 chore: Release v5.20.0 [skip ci]
# [5.20.0](https://github.com/ReVanced/revanced-patches/compare/v5.19.1...v5.20.0) (2025-04-15)

### Bug Fixes

* **Duolingo - Hide ads:**  Support lastest app release ([#4790](https://github.com/ReVanced/revanced-patches/issues/4790)) ([3d6958f](3d6958f157))
* **Spotify - Unlock Spotify Premium:** Remove premium restriction for 'Spotify Connect' ([#4782](https://github.com/ReVanced/revanced-patches/issues/4782)) ([50f5b1a](50f5b1ac54))
* **Spotify:** Fix login by replacing `Spoof signature` patch with new `Spoof package info` patch ([#4794](https://github.com/ReVanced/revanced-patches/issues/4794)) ([0f687ec](0f687ecfd3))
* **YouTube - Remove background playback restrictions:** Restore PiP button functionality after screen is unlocked ([b4e8540](b4e8540bbc))

### Features

* Add `Set target SDK version 34` patch (Disable edge-to-edge display) ([#4780](https://github.com/ReVanced/revanced-patches/issues/4780)) ([9db67a6](9db67a6eb2))
* **Spotify - Custom theme:** Add option to use unmodified player background gradient ([#4741](https://github.com/ReVanced/revanced-patches/issues/4741)) ([c510931](c510931eb0))
* **YouTube - Swipe controls:** Add option to change volume swipe sensitivity (step size) ([#4557](https://github.com/ReVanced/revanced-patches/issues/4557)) ([5ebd449](5ebd449f1f))
2025-04-15 11:02:58 +00:00
oSumAtrIX
7fbd26ccad chore: Merge branch dev to main (#4781) 2025-04-15 12:59:44 +02:00
github-actions[bot]
91995ea01d chore: Sync translations (#4795)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-04-15 12:57:13 +02:00
semantic-release-bot
86f867fe97 chore: Release v5.20.0-dev.7 [skip ci]
# [5.20.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.6...v5.20.0-dev.7) (2025-04-15)

### Bug Fixes

* **Spotify:** Fix login by replacing `Spoof signature` patch with new `Spoof package info` patch ([#4794](https://github.com/ReVanced/revanced-patches/issues/4794)) ([0f687ec](0f687ecfd3))
2025-04-15 10:56:12 +00:00
oSumAtrIX
0f687ecfd3 fix(Spotify): Fix login by replacing Spoof signature patch with new Spoof package info patch (#4794)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-04-15 12:53:26 +02:00
semantic-release-bot
6c8b7d09c1 chore: Release v5.20.0-dev.6 [skip ci]
# [5.20.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.5...v5.20.0-dev.6) (2025-04-15)

### Bug Fixes

* **Duolingo - Hide ads:**  Support lastest app release ([#4790](https://github.com/ReVanced/revanced-patches/issues/4790)) ([3d6958f](3d6958f157))
2025-04-15 07:27:06 +00:00
hoodles
3d6958f157 fix(Duolingo - Hide ads): Support lastest app release (#4790) 2025-04-15 09:24:29 +02:00
semantic-release-bot
43d7cc7374 chore: Release v5.20.0-dev.5 [skip ci]
# [5.20.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.4...v5.20.0-dev.5) (2025-04-14)

### Features

* **YouTube - Swipe controls:** Add option to change volume swipe sensitivity (step size) ([#4557](https://github.com/ReVanced/revanced-patches/issues/4557)) ([5ebd449](5ebd449f1f))
2025-04-14 08:46:51 +00:00
Kamil Kras
5ebd449f1f feat(YouTube - Swipe controls): Add option to change volume swipe sensitivity (step size) (#4557)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-04-14 10:43:21 +02:00
semantic-release-bot
346a061df8 chore: Release v5.20.0-dev.4 [skip ci]
# [5.20.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.3...v5.20.0-dev.4) (2025-04-14)

### Bug Fixes

* **Spotify - Unlock Spotify Premium:** Remove premium restriction for 'Spotify Connect' ([#4782](https://github.com/ReVanced/revanced-patches/issues/4782)) ([50f5b1a](50f5b1ac54))
2025-04-14 08:10:14 +00:00
semantic-release-bot
13e490a422 chore: Release v5.20.0-dev.3 [skip ci]
# [5.20.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.2...v5.20.0-dev.3) (2025-04-13)

### Bug Fixes

* **YouTube - Remove background playback restrictions:** Restore PiP button functionality after screen is unlocked ([b4e8540](b4e8540bbc))
2025-04-13 22:11:10 +00:00
LisoUseInAIKyrios
b4e8540bbc fix(YouTube - Remove background playback restrictions): Restore PiP button functionality after screen is unlocked 2025-04-14 00:07:35 +02:00
github-actions[bot]
775c1baec2 chore: Sync translations (#4784) 2025-04-14 00:05:17 +02:00
semantic-release-bot
9419fb8ec4 chore: Release v5.20.0-dev.2 [skip ci]
# [5.20.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.20.0-dev.1...v5.20.0-dev.2) (2025-04-13)

### Features

* **Spotify - Custom theme:** Add option to use unmodified player background gradient ([#4741](https://github.com/ReVanced/revanced-patches/issues/4741)) ([c510931](c510931eb0))
2025-04-13 19:29:33 +00:00
Nuckyz
c510931eb0 feat(Spotify - Custom theme): Add option to use unmodified player background gradient (#4741)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
2025-04-13 21:26:59 +02:00
semantic-release-bot
7160699384 chore: Release v5.20.0-dev.1 [skip ci]
# [5.20.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.1...v5.20.0-dev.1) (2025-04-13)

### Features

* Add `Set target SDK version 34` patch (Disable edge-to-edge display) ([#4780](https://github.com/ReVanced/revanced-patches/issues/4780)) ([9db67a6](9db67a6eb2))
2025-04-13 16:26:18 +00:00
LisoUseInAIKyrios
9db67a6eb2 feat: Add Set target SDK version 34 patch (Disable edge-to-edge display) (#4780)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-04-13 18:23:45 +02:00
semantic-release-bot
e684d87dd3 chore: Release v5.19.1 [skip ci]
## [5.19.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.0...v5.19.1) (2025-04-12)

### Bug Fixes

* **Google Photos:** Restore patching with ReVanced Manager ([#4773](https://github.com/ReVanced/revanced-patches/issues/4773)) ([d451bc6](d451bc6d6d))
* **Spotify:** Restore patching with ReVanced Manager ([#4769](https://github.com/ReVanced/revanced-patches/issues/4769)) ([89d44da](89d44da171))
2025-04-12 19:30:34 +00:00
LisoUseInAIKyrios
2d1752a1eb chore: Merge branch dev to main (#4772) 2025-04-12 21:27:49 +02:00
semantic-release-bot
c9ff7092fe chore: Release v5.19.1-dev.2 [skip ci]
## [5.19.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.19.1-dev.1...v5.19.1-dev.2) (2025-04-12)

### Bug Fixes

* **Google Photos:** Restore patching with ReVanced Manager ([#4773](https://github.com/ReVanced/revanced-patches/issues/4773)) ([d451bc6](d451bc6d6d))
2025-04-12 19:23:37 +00:00
LisoUseInAIKyrios
d451bc6d6d fix(Google Photos): Restore patching with ReVanced Manager (#4773) 2025-04-12 21:20:36 +02:00
semantic-release-bot
741fd36872 chore: Release v5.19.1-dev.1 [skip ci]
## [5.19.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.19.0...v5.19.1-dev.1) (2025-04-12)

### Bug Fixes

* **Spotify:** Restore patching with ReVanced Manager ([#4769](https://github.com/ReVanced/revanced-patches/issues/4769)) ([89d44da](89d44da171))
2025-04-12 19:04:28 +00:00
semantic-release-bot
517f8cf59a chore: Release v5.19.0 [skip ci]
# [5.19.0](https://github.com/ReVanced/revanced-patches/compare/v5.18.0...v5.19.0) (2025-04-12)

### Bug Fixes

* **Google Photos - Restore hidden 'Back up while charging' toggle:** Constrain to last working app target ([#4761](https://github.com/ReVanced/revanced-patches/issues/4761)) ([e6ae55f](e6ae55fa99))
* **Google Photos:** Remove obsolete non functional patch `Restore hidden 'Back up while charging' toggle` ([#4764](https://github.com/ReVanced/revanced-patches/issues/4764)) ([f68d06d](f68d06dbf3))
* **Spotify - Custom theme:** Override more color resources ([#4690](https://github.com/ReVanced/revanced-patches/issues/4690)) ([49c8499](49c849979f))
* **Spotify - Unlock Spotify Premium:** Remove restrictions for Google voice assistant ([#4702](https://github.com/ReVanced/revanced-patches/issues/4702)) ([d573386](d573386e0f))
* **Spotify:** Remove ads sections from home ([#4722](https://github.com/ReVanced/revanced-patches/issues/4722)) ([628d184](628d18489c))
* **Twitter - Hide recommended users:** Make hiding work again by filtering for new entryId prefix ([#4456](https://github.com/ReVanced/revanced-patches/issues/4456)) ([3d68c06](3d68c06146))
* **YouTube - Hide layout components:** Do not hide video description music/game links if hide horizontal shelves is enabled ([6005c97](6005c97bf5))
* **YouTube - Hide player flyout menu items:** Show more detailed summary text for 'Hide Audio track' if using Android spoof client ([#4756](https://github.com/ReVanced/revanced-patches/issues/4756)) ([1abed31](1abed31968))
* **YouTube - Remove background playback restrictions:** Do not show media controls when playing Shorts from the feed ([318b55b](318b55b8fe))
* **YouTube - Return YouTube Dislike:** Correctly update label after disliking a Short with 20.07 ([0bff207](0bff207efc))
* **YouTube - Return YouTube Dislike:** Fix inconsistent label after disliking a Short ([3d67d90](3d67d90473))
* **YouTube - Seekbar:** Correctly hide the feed seekbar with target 20.07 ([2035c9e](2035c9e2e9))
* **YouTube:** Combine multiple seekbar patches into a single patch ([#4705](https://github.com/ReVanced/revanced-patches/issues/4705)) ([37984b8](37984b8b99))

### Features

* **Angulus:** Add `Hide ads` patch ([#4604](https://github.com/ReVanced/revanced-patches/issues/4604)) ([2d7b1b0](2d7b1b09af))
* **Messenger:** Add `Remove Meta AI tab` patch ([#4726](https://github.com/ReVanced/revanced-patches/issues/4726)) ([de0d11f](de0d11fcfb))
* **Photomath:** Support latest version ([#4672](https://github.com/ReVanced/revanced-patches/issues/4672)) ([ef3d5ba](ef3d5bafd5))
* **Proton Mail:** Add `Remove 'Sent from' signature` patch ([#4514](https://github.com/ReVanced/revanced-patches/issues/4514)) ([8ed9d5b](8ed9d5bf08))
* **Spotify:** Add `Check environment` patch ([#4765](https://github.com/ReVanced/revanced-patches/issues/4765)) ([854a18f](854a18ff72))
* **Spotify:** Add limited support for version `8.6.98.900` (last version that supports Kenwood and Pioneer car stereos) ([#4750](https://github.com/ReVanced/revanced-patches/issues/4750)) ([e30f593](e30f593af0))
* **Strava - Disable subscription suggestions:** Make compatible with latest version ([#4739](https://github.com/ReVanced/revanced-patches/issues/4739)) ([654587a](654587a75e))
* **YouTube - Settings:** Add icons to the ReVanced settings ([#4496](https://github.com/ReVanced/revanced-patches/issues/4496)) ([fdefb67](fdefb67d02))
2025-04-12 13:27:56 +00:00
oSumAtrIX
b78fb24435 chore: Merge branch dev to main (#4699)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: semantic-release-bot <semantic-release-bot@martynus.net>
Co-authored-by: Denis Kerner <11692788+dtricks@users.noreply.github.com>
Co-authored-by: Denis Kerner <denis.kerner@vodafone.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
Co-authored-by: Dawid Krajcarz <80264606+drobotk@users.noreply.github.com>
Co-authored-by: Jakub Blažej <trogper@gmail.com>
Co-authored-by: MarcaD <152095496+MarcaDian@users.noreply.github.com>
Co-authored-by: Aoife McCullough <92225779+AoifeMcCull@users.noreply.github.com>
Co-authored-by: Nuckyz <61953774+Nuckyz@users.noreply.github.com>
Co-authored-by: user5095 <140261471+user5095@users.noreply.github.com>
Co-authored-by: Brosssh <44944126+Brosssh@users.noreply.github.com>
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
Co-authored-by: oSumAtrIX <github@osumatrix.me>
2025-04-12 15:24:43 +02:00
github-actions[bot]
a3faccb21b chore: Sync translations (#4766)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-04-12 15:19:43 +02:00
semantic-release-bot
5f0fddc122 chore: Release v5.19.0-dev.17 [skip ci]
# [5.19.0-dev.17](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.16...v5.19.0-dev.17) (2025-04-12)

### Features

* **Spotify:** Add `Check environment` patch ([#4765](https://github.com/ReVanced/revanced-patches/issues/4765)) ([854a18f](854a18ff72))
2025-04-12 12:56:01 +00:00
oSumAtrIX
854a18ff72 feat(Spotify): Add Check environment patch (#4765) 2025-04-12 14:53:27 +02:00
semantic-release-bot
b994a16bdc chore: Release v5.19.0-dev.16 [skip ci]
# [5.19.0-dev.16](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.15...v5.19.0-dev.16) (2025-04-11)

### Bug Fixes

* **Google Photos:** Remove obsolete non functional patch `Restore hidden 'Back up while charging' toggle` ([#4764](https://github.com/ReVanced/revanced-patches/issues/4764)) ([f68d06d](f68d06dbf3))
2025-04-11 20:15:09 +00:00
LisoUseInAIKyrios
f68d06dbf3 fix(Google Photos): Remove obsolete non functional patch Restore hidden 'Back up while charging' toggle (#4764) 2025-04-11 22:12:13 +02:00
semantic-release-bot
04c6a2e5f4 chore: Release v5.19.0-dev.15 [skip ci]
# [5.19.0-dev.15](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.14...v5.19.0-dev.15) (2025-04-11)

### Bug Fixes

* **Google Photos - Restore hidden 'Back up while charging' toggle:** Constrain to last working app target ([#4761](https://github.com/ReVanced/revanced-patches/issues/4761)) ([e6ae55f](e6ae55fa99))
2025-04-11 19:42:49 +00:00
LisoUseInAIKyrios
e6ae55fa99 fix(Google Photos - Restore hidden 'Back up while charging' toggle): Constrain to last working app target (#4761) 2025-04-11 21:40:17 +02:00
github-actions[bot]
fb62474ff4 chore: Sync translations (#4763)
Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2025-04-11 21:39:34 +02:00
semantic-release-bot
e084f01fd0 chore: Release v5.19.0-dev.14 [skip ci]
# [5.19.0-dev.14](https://github.com/ReVanced/revanced-patches/compare/v5.19.0-dev.13...v5.19.0-dev.14) (2025-04-11)

### Bug Fixes

* **Spotify - Unlock Spotify Premium:** Remove restrictions for Google voice assistant ([#4702](https://github.com/ReVanced/revanced-patches/issues/4702)) ([d573386](d573386e0f))
2025-04-11 19:36:38 +00:00
Brosssh
d573386e0f fix(Spotify - Unlock Spotify Premium): Remove restrictions for Google voice assistant (#4702)
Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com>
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2025-04-11 21:33:59 +02:00
629 changed files with 42338 additions and 22379 deletions

View File

@@ -13,17 +13,15 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
distribution: 'temurin'
java-version: '17'
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
uses: burrunan/gradle-cache-action@v3
- name: Build
env:

View File

@@ -17,7 +17,6 @@ jobs:
uses: actions/checkout@v4
with:
ref: dev
fetch-depth: 0
clean: true
- name: Pull strings

View File

@@ -15,8 +15,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Preprocess strings
env:

View File

@@ -13,24 +13,21 @@ jobs:
permissions:
contents: write
packages: write
id-token: write
attestations: write
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# Make sure the release step uses its own credentials:
# https://github.com/cycjimmy/semantic-release-action#private-packages
persist-credentials: false
fetch-depth: 0
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: "temurin"
java-version: "17"
distribution: 'temurin'
java-version: '17'
- name: Cache Gradle
uses: burrunan/gradle-cache-action@v1
uses: burrunan/gradle-cache-action@v3
- name: Build
env:
@@ -40,7 +37,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
node-version: 'lts/*'
cache: 'npm'
- name: Install dependencies
@@ -54,6 +51,14 @@ jobs:
fingerprint: ${{ vars.GPG_FINGERPRINT }}
- name: Release
uses: cycjimmy/semantic-release-action@v4
id: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm exec semantic-release
- name: Attest
if: steps.release.outputs.new_release_published == 'true'
uses: actions/attest-build-provenance@v2
with:
subject-name: 'ReVanced Patches ${{ steps.release.outputs.new_release_git_tag }}'
subject-path: patches/build/libs/patches-*.rvp

View File

@@ -22,7 +22,7 @@
{
"assets": [
"CHANGELOG.md",
"gradle.properties",
"gradle.properties"
],
"message": "chore: Release v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
@@ -33,16 +33,16 @@
"assets": [
{
"path": "patches/build/libs/patches-!(*sources*|*javadoc*).rvp?(.asc)"
},
}
],
successComment: false
"successComment": false
}
],
[
"@saithodev/semantic-release-backmerge",
{
backmergeBranches: [{"from": "main", "to": "dev"}],
clearWorkspace: true
"backmergeBranches": [{"from": "main", "to": "dev"}],
"clearWorkspace": true
}
]
]

File diff suppressed because it is too large Load Diff

3
build.gradle.kts Normal file
View File

@@ -0,0 +1,3 @@
plugins {
alias(libs.plugins.android.library) apply false
}

View File

@@ -0,0 +1,16 @@
android {
namespace = "app.revanced.extension"
defaultConfig {
minSdk = 21
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}
dependencies {
compileOnly(libs.annotation)
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,28 @@
package app.revanced.extension.all.misc.hide.adb;
import android.content.ContentResolver;
import android.provider.Settings;
import java.util.Arrays;
import java.util.List;
@SuppressWarnings("unused")
public final class HideAdbPatch {
private static final List<String> SPOOF_SETTINGS = Arrays.asList("adb_enabled", "adb_wifi_enabled", "development_settings_enabled");
public static int getInt(ContentResolver cr, String name) throws Settings.SettingNotFoundException {
if (SPOOF_SETTINGS.contains(name)) {
return 0;
}
return Settings.Global.getInt(cr, name);
}
public static int getInt(ContentResolver cr, String name, int def) {
if (SPOOF_SETTINGS.contains(name)) {
return 0;
}
return Settings.Global.getInt(cr, name, def);
}
}

View File

@@ -1,4 +1,4 @@
package app.revanced.extension.all.connectivity.wifi.spoof;
package app.revanced.extension.all.misc.connectivity.wifi.spoof;
import android.app.PendingIntent;
import android.content.Context;

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

View File

@@ -0,0 +1,4 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
compileOnly(project(":extensions:cricbuzz:stub"))
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,28 @@
package app.revanced.extension.cricbuzz.ads;
import com.cricbuzz.android.data.rest.model.BottomBar;
import java.util.List;
import java.util.Iterator;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public class HideAdsPatch {
/**
* Injection point.
*/
public static void filterCb11(List<BottomBar> list) {
try {
Iterator<BottomBar> iterator = list.iterator();
while (iterator.hasNext()) {
BottomBar bar = iterator.next();
if (bar.getName().equals("Cricbuzz11")) {
Logger.printInfo(() -> "Removing Cricbuzz11 bar: " + bar);
iterator.remove();
}
}
} catch (Exception ex) {
Logger.printException(() -> "filterCb11 failure", ex);
}
}
}

View File

@@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "app.revanced.extension"
compileSdk = 34
defaultConfig {
minSdk = 21
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,5 @@
package com.cricbuzz.android.data.rest.model;
public final class BottomBar {
public final String getName() { throw new UnsupportedOperationException(); }
}

View File

@@ -0,0 +1,3 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,25 @@
package app.revanced.extension.messenger.metaai;
import java.util.*;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public class RemoveMetaAIPatch {
private static final Set<Long> loggedIDs = Collections.synchronizedSet(new HashSet<>());
public static boolean overrideBooleanFlag(long id, boolean value) {
try {
if (Long.toString(id).startsWith("REPLACED_BY_PATCH")) {
if (loggedIDs.add(id))
Logger.printInfo(() -> "Overriding " + id + " from " + value + " to false");
return false;
}
} catch (Exception ex) {
Logger.printException(() -> "overrideBooleanFlag failure", ex);
}
return value;
}
}

View File

@@ -82,7 +82,7 @@ public class HideAdsPatch {
// Filter HeaderBlock with known ads until next HeaderBlock.
if (currentBlock instanceof HeaderBlock headerBlock) {
StyledText headerText = headerBlock.component20();
StyledText headerText = headerBlock.getTitle();
if (headerText != null) {
skipFullHeader = false;
for (String blockedHeaderBlock : blockedHeaderBlocks) {

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

View File

@@ -3,8 +3,7 @@ package nl.nu.performance.api.client.objects;
import nl.nu.performance.api.client.interfaces.Block;
public class HeaderBlock extends Block {
// returns title
public final StyledText component20() {
public final StyledText getTitle() {
throw new UnsupportedOperationException("Stub");
}
}

View File

@@ -0,0 +1,4 @@
dependencies {
compileOnly(project(":extensions:shared:library"))
compileOnly(project(":extensions:primevideo:stub"))
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,36 @@
package app.revanced.extension.primevideo.ads;
import com.amazon.avod.fsm.SimpleTrigger;
import com.amazon.avod.media.ads.AdBreak;
import com.amazon.avod.media.ads.internal.state.AdBreakTrigger;
import com.amazon.avod.media.ads.internal.state.AdEnabledPlayerTriggerType;
import com.amazon.avod.media.playback.VideoPlayer;
import com.amazon.avod.media.ads.internal.state.ServerInsertedAdBreakState;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public final class SkipAdsPatch {
public static void enterServerInsertedAdBreakState(ServerInsertedAdBreakState state, AdBreakTrigger trigger, VideoPlayer player) {
try {
AdBreak adBreak = trigger.getBreak();
// There are two scenarios when entering the original method:
// 1. Player naturally entered an ad break while watching a video.
// 2. User is skipped/scrubbed to a position on the timeline. If seek position is past an ad break,
// user is forced to watch an ad before continuing.
//
// Scenario 2 is indicated by trigger.getSeekStartPosition() != null, so skip directly to the scrubbing
// target. Otherwise, just calculate when the ad break should end and skip to there.
if (trigger.getSeekStartPosition() != null)
player.seekTo(trigger.getSeekTarget().getTotalMilliseconds());
else
player.seekTo(player.getCurrentPosition() + adBreak.getDurationExcludingAux().getTotalMilliseconds());
// Send "end of ads" trigger to state machine so everything doesn't get whacky.
state.doTrigger(new SimpleTrigger(AdEnabledPlayerTriggerType.NO_MORE_ADS_SKIP_TRANSITION));
} catch (Exception ex) {
Logger.printException(() -> "Failed skipping ads", ex);
}
}
}

View File

@@ -0,0 +1,207 @@
package app.revanced.extension.primevideo.videoplayer;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.RectF;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import java.util.Arrays;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import com.amazon.video.sdk.player.Player;
public class PlaybackSpeedPatch {
private static Player player;
private static final float[] SPEED_VALUES = {0.5f, 0.7f, 0.8f, 0.9f, 0.95f, 1.0f, 1.05f, 1.1f, 1.2f, 1.3f, 1.5f, 2.0f};
private static final String SPEED_BUTTON_TAG = "speed_overlay";
public static void setPlayer(Player playerInstance) {
player = playerInstance;
if (player != null) {
// Reset playback rate when switching between episodes to ensure correct display.
player.setPlaybackRate(1.0f);
}
}
public static void initializeSpeedOverlay(View userControlsView) {
try {
LinearLayout buttonContainer = Utils.getChildViewByResourceName(userControlsView, "ButtonContainerPlayerTop");
// If the speed overlay exists we should return early.
if (Utils.getChildView(buttonContainer, false, child ->
child instanceof ImageView && SPEED_BUTTON_TAG.equals(child.getTag())) != null) {
return;
}
ImageView speedButton = createSpeedButton(userControlsView.getContext());
speedButton.setOnClickListener(v -> changePlaybackSpeed(speedButton));
buttonContainer.addView(speedButton, 0);
} catch (IllegalArgumentException e) {
Logger.printException(() -> "initializeSpeedOverlay, no button container found", e);
} catch (Exception e) {
Logger.printException(() -> "initializeSpeedOverlay failure", e);
}
}
private static ImageView createSpeedButton(Context context) {
ImageView speedButton = new ImageView(context);
speedButton.setContentDescription("Playback Speed");
speedButton.setTag(SPEED_BUTTON_TAG);
speedButton.setClickable(true);
speedButton.setFocusable(true);
speedButton.setScaleType(ImageView.ScaleType.CENTER);
SpeedIconDrawable speedIcon = new SpeedIconDrawable();
speedButton.setImageDrawable(speedIcon);
int buttonSize = Utils.dipToPixels(48);
speedButton.setMinimumWidth(buttonSize);
speedButton.setMinimumHeight(buttonSize);
return speedButton;
}
private static String[] getSpeedOptions() {
String[] options = new String[SPEED_VALUES.length];
for (int i = 0; i < SPEED_VALUES.length; i++) {
options[i] = SPEED_VALUES[i] + "x";
}
return options;
}
private static void changePlaybackSpeed(ImageView imageView) {
if (player == null) {
Logger.printException(() -> "Player not available");
return;
}
try {
player.pause();
AlertDialog dialog = createSpeedPlaybackDialog(imageView);
dialog.setOnDismissListener(dialogInterface -> player.play());
dialog.show();
} catch (Exception e) {
Logger.printException(() -> "changePlaybackSpeed", e);
}
}
private static AlertDialog createSpeedPlaybackDialog(ImageView imageView) {
Context context = imageView.getContext();
int currentSelection = getCurrentSpeedSelection();
return new AlertDialog.Builder(context)
.setTitle("Select Playback Speed")
.setSingleChoiceItems(getSpeedOptions(), currentSelection,
PlaybackSpeedPatch::handleSpeedSelection)
.create();
}
private static int getCurrentSpeedSelection() {
try {
float currentRate = player.getPlaybackRate();
int index = Arrays.binarySearch(SPEED_VALUES, currentRate);
return Math.max(index, 0); // Use slowest speed if not found.
} catch (Exception e) {
Logger.printException(() -> "getCurrentSpeedSelection error getting current playback speed", e);
return 0;
}
}
private static void handleSpeedSelection(android.content.DialogInterface dialog, int selectedIndex) {
try {
float selectedSpeed = SPEED_VALUES[selectedIndex];
player.setPlaybackRate(selectedSpeed);
player.play();
} catch (Exception e) {
Logger.printException(() -> "handleSpeedSelection error setting playback speed", e);
} finally {
dialog.dismiss();
}
}
}
class SpeedIconDrawable extends Drawable {
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
@Override
public void draw(Canvas canvas) {
int w = getBounds().width();
int h = getBounds().height();
float centerX = w / 2f;
// Position gauge in lower portion.
float centerY = h * 0.7f;
float radius = Math.min(w, h) / 2f * 0.8f;
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(radius * 0.1f);
// Draw semicircle.
RectF oval = new RectF(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
canvas.drawArc(oval, 180, 180, false, paint);
// Draw three tick marks.
paint.setStrokeWidth(radius * 0.06f);
for (int i = 0; i < 3; i++) {
float angle = 180 + (i * 45); // 180°, 225°, 270°.
float angleRad = (float) Math.toRadians(angle);
float startX = centerX + (radius * 0.8f) * (float) Math.cos(angleRad);
float startY = centerY + (radius * 0.8f) * (float) Math.sin(angleRad);
float endX = centerX + radius * (float) Math.cos(angleRad);
float endY = centerY + radius * (float) Math.sin(angleRad);
canvas.drawLine(startX, startY, endX, endY, paint);
}
// Draw needle.
paint.setStrokeWidth(radius * 0.08f);
float needleAngle = 200; // Slightly right of center.
float needleAngleRad = (float) Math.toRadians(needleAngle);
float needleEndX = centerX + (radius * 0.6f) * (float) Math.cos(needleAngleRad);
float needleEndY = centerY + (radius * 0.6f) * (float) Math.sin(needleAngleRad);
canvas.drawLine(centerX, centerY, needleEndX, needleEndY, paint);
// Center dot.
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(centerX, centerY, radius * 0.06f, paint);
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
paint.setColorFilter(colorFilter);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public int getIntrinsicWidth() {
return Utils.dipToPixels(32);
}
@Override
public int getIntrinsicHeight() {
return Utils.dipToPixels(32);
}
}

View File

@@ -0,0 +1,17 @@
plugins {
alias(libs.plugins.android.library)
}
android {
namespace = "app.revanced.extension"
compileSdk = 34
defaultConfig {
minSdk = 21
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}

View File

@@ -0,0 +1 @@
<manifest/>

View File

@@ -0,0 +1,6 @@
package com.amazon.avod.fsm;
public final class SimpleTrigger<T> implements Trigger<T> {
public SimpleTrigger(T triggerType) {
}
}

View File

@@ -0,0 +1,7 @@
package com.amazon.avod.fsm;
public abstract class StateBase<S, T> {
// This method orginally has protected access (modified in patch code).
public void doTrigger(Trigger<T> trigger) {
}
}

View File

@@ -0,0 +1,4 @@
package com.amazon.avod.fsm;
public interface Trigger<T> {
}

View File

@@ -0,0 +1,7 @@
package com.amazon.avod.media;
public final class TimeSpan {
public long getTotalMilliseconds() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,7 @@
package com.amazon.avod.media.ads;
import com.amazon.avod.media.TimeSpan;
public interface AdBreak {
TimeSpan getDurationExcludingAux();
}

View File

@@ -0,0 +1,4 @@
package com.amazon.avod.media.ads.internal.state;
public abstract class AdBreakState extends AdEnabledPlaybackState {
}

View File

@@ -0,0 +1,18 @@
package com.amazon.avod.media.ads.internal.state;
import com.amazon.avod.media.ads.AdBreak;
import com.amazon.avod.media.TimeSpan;
public class AdBreakTrigger {
public AdBreak getBreak() {
throw new UnsupportedOperationException();
}
public TimeSpan getSeekTarget() {
throw new UnsupportedOperationException();
}
public TimeSpan getSeekStartPosition() {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,8 @@
package com.amazon.avod.media.ads.internal.state;
import com.amazon.avod.fsm.StateBase;
import com.amazon.avod.media.playback.state.PlayerStateType;
import com.amazon.avod.media.playback.state.trigger.PlayerTriggerType;
public class AdEnabledPlaybackState extends StateBase<PlayerStateType, PlayerTriggerType> {
}

View File

@@ -0,0 +1,5 @@
package com.amazon.avod.media.ads.internal.state;
public enum AdEnabledPlayerTriggerType {
NO_MORE_ADS_SKIP_TRANSITION
}

View File

@@ -0,0 +1,4 @@
package com.amazon.avod.media.ads.internal.state;
public class ServerInsertedAdBreakState extends AdBreakState {
}

View File

@@ -0,0 +1,13 @@
package com.amazon.avod.media.playback;
public interface VideoPlayer {
long getCurrentPosition();
void seekTo(long positionMs);
void pause();
void play();
boolean isPlaying();
}

View File

@@ -0,0 +1,4 @@
package com.amazon.avod.media.playback.state;
public interface PlayerStateType {
}

View File

@@ -0,0 +1,4 @@
package com.amazon.avod.media.playback.state.trigger;
public interface PlayerTriggerType {
}

View File

@@ -0,0 +1,11 @@
package com.amazon.video.sdk.player;
public interface Player {
float getPlaybackRate();
void setPlaybackRate(float rate);
void play();
void pause();
}

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

View File

@@ -1,5 +1,5 @@
plugins {
id("com.android.library")
alias(libs.plugins.android.library)
}
android {

View File

@@ -1,10 +1,11 @@
package app.revanced.extension.shared;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.requests.Route.Method.GET;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.SearchManager;
import android.content.Context;
import android.content.DialogInterface;
@@ -14,15 +15,20 @@ import android.net.Uri;
import android.os.Build;
import android.os.PowerManager;
import android.provider.Settings;
import android.util.Pair;
import android.widget.LinearLayout;
import androidx.annotation.RequiresApi;
import androidx.annotation.Nullable;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Locale;
/**
* @noinspection unused
*/
import app.revanced.extension.shared.requests.Requester;
import app.revanced.extension.shared.requests.Route;
@SuppressWarnings("unused")
public class GmsCoreSupport {
private static final String PACKAGE_NAME_YOUTUBE = "com.google.android.youtube";
private static final String PACKAGE_NAME_YOUTUBE_MUSIC = "com.google.android.apps.youtube.music";
@@ -31,10 +37,24 @@ public class GmsCoreSupport {
= getGmsCoreVendorGroupId() + ".android.gms";
private static final Uri GMS_CORE_PROVIDER
= Uri.parse("content://" + getGmsCoreVendorGroupId() + ".android.gsf.gservices/prefix");
private static final String DONT_KILL_MY_APP_LINK
= "https://dontkillmyapp.com";
private static final String DONT_KILL_MY_APP_URL
= "https://dontkillmyapp.com/";
private static final Route DONT_KILL_MY_APP_MANUFACTURER_API
= new Route(GET, "/api/v2/{manufacturer}.json");
private static final String DONT_KILL_MY_APP_NAME_PARAMETER
= "?app=MicroG";
private static final String BUILD_MANUFACTURER
= Build.MANUFACTURER.toLowerCase(Locale.ROOT).replace(" ", "-");
/**
* If a manufacturer specific page exists on DontKillMyApp.
*/
@Nullable
private static volatile Boolean DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED;
private static void open(String queryOrLink) {
Logger.printInfo(() -> "Opening link: " + queryOrLink);
Intent intent;
try {
// Check if queryOrLink is a valid URL.
@@ -59,13 +79,27 @@ public class GmsCoreSupport {
// Use a delay to allow the activity to finish initializing.
// Otherwise, if device is in dark mode the dialog is shown with wrong color scheme.
Utils.runOnMainThreadDelayed(() -> {
// Create the custom dialog.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
context,
str("gms_core_dialog_title"), // Title.
str(dialogMessageRef), // Message.
null, // No EditText.
str(positiveButtonTextRef), // OK button text.
() -> onPositiveClickListener.onClick(null, 0), // Convert DialogInterface.OnClickListener to Runnable.
null, // No Cancel button action.
null, // No Neutral button text.
null, // No Neutral button action.
true // Dismiss dialog when onNeutralClick.
);
Dialog dialog = dialogPair.first;
// Do not set cancelable to false, to allow using back button to skip the action,
// just in case the battery change can never be satisfied.
var dialog = new AlertDialog.Builder(context)
.setTitle(str("gms_core_dialog_title"))
.setMessage(str(dialogMessageRef))
.setPositiveButton(str(positiveButtonTextRef), onPositiveClickListener)
.create();
dialog.setCancelable(true);
// Show the dialog
Utils.showDialog(context, dialog);
}, 100);
}
@@ -73,7 +107,6 @@ public class GmsCoreSupport {
/**
* Injection point.
*/
@RequiresApi(api = Build.VERSION_CODES.N)
public static void checkGmsCore(Activity context) {
try {
// Verify the user has not included GmsCore for a root installation.
@@ -88,7 +121,7 @@ public class GmsCoreSupport {
// Do not exit. If the app exits before launch completes (and without
// opening another activity), then on some devices such as Pixel phone Android 10
// no toast will be shown and the app will continually be relaunched
// no toast will be shown and the app will continually relaunch
// with the appearance of a hung app.
}
@@ -121,15 +154,20 @@ public class GmsCoreSupport {
}
// Check if GmsCore is currently running in the background.
try (var client = context.getContentResolver().acquireContentProviderClient(GMS_CORE_PROVIDER)) {
var client = context.getContentResolver().acquireContentProviderClient(GMS_CORE_PROVIDER);
//noinspection TryFinallyCanBeTryWithResources
try {
if (client == null) {
Logger.printInfo(() -> "GmsCore is not running in the background");
checkIfDontKillMyAppSupportsManufacturer();
showBatteryOptimizationDialog(context,
"gms_core_dialog_not_whitelisted_not_allowed_in_background_message",
"gms_core_dialog_open_website_text",
(dialog, id) -> open(DONT_KILL_MY_APP_LINK));
(dialog, id) -> openDontKillMyApp());
}
} finally {
if (client != null) client.close();
}
} catch (Exception ex) {
Logger.printException(() -> "checkGmsCore failure", ex);
@@ -143,10 +181,57 @@ public class GmsCoreSupport {
activity.startActivityForResult(intent, 0);
}
private static void checkIfDontKillMyAppSupportsManufacturer() {
Utils.runOnBackgroundThread(() -> {
try {
final long start = System.currentTimeMillis();
HttpURLConnection connection = Requester.getConnectionFromRoute(
DONT_KILL_MY_APP_URL, DONT_KILL_MY_APP_MANUFACTURER_API, BUILD_MANUFACTURER);
connection.setConnectTimeout(5000);
connection.setReadTimeout(5000);
final boolean supported = connection.getResponseCode() == 200;
Logger.printInfo(() -> "Manufacturer is " + (supported ? "" : "NOT ")
+ "listed on DontKillMyApp: " + BUILD_MANUFACTURER
+ " fetch took: " + (System.currentTimeMillis() - start) + "ms");
DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED = supported;
} catch (Exception ex) {
Logger.printInfo(() -> "Could not check if manufacturer is listed on DontKillMyApp: "
+ BUILD_MANUFACTURER, ex);
DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED = null;
}
});
}
private static void openDontKillMyApp() {
final Boolean manufacturerSupported = DONT_KILL_MY_APP_MANUFACTURER_SUPPORTED;
String manufacturerPageToOpen;
if (manufacturerSupported == null) {
// Fetch has not completed yet. Only happens on extremely slow internet connections
// and the user spends less than 1 second reading what's on screen.
// Instead of waiting for the fetch (which may timeout),
// open the website without a vendor.
manufacturerPageToOpen = "";
} else if (manufacturerSupported) {
manufacturerPageToOpen = BUILD_MANUFACTURER;
} else {
// No manufacturer specific page exists. Open the general page.
manufacturerPageToOpen = "general";
}
open(DONT_KILL_MY_APP_URL + manufacturerPageToOpen + DONT_KILL_MY_APP_NAME_PARAMETER);
}
/**
* @return If GmsCore is not whitelisted from battery optimizations.
*/
private static boolean batteryOptimizationsEnabled(Context context) {
//noinspection ObsoleteSdkInt
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
// Android 5.0 does not have battery optimization settings.
return false;
}
var powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
return !powerManager.isIgnoringBatteryOptimizations(GMS_CORE_PACKAGE_NAME);
}

View File

@@ -1,15 +1,27 @@
package app.revanced.extension.shared;
import static app.revanced.extension.shared.settings.BaseSettings.DEBUG;
import static app.revanced.extension.shared.settings.BaseSettings.DEBUG_STACKTRACE;
import static app.revanced.extension.shared.settings.BaseSettings.DEBUG_TOAST_ON_ERROR;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.settings.BaseSettings;
import java.io.PrintWriter;
import java.io.StringWriter;
import static app.revanced.extension.shared.settings.BaseSettings.*;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.preference.LogBufferManager;
/**
* ReVanced specific logger. Logging is done to standard device log (accessible thru ADB),
* and additionally accessible thru {@link LogBufferManager}.
*
* All methods are thread safe, and are safe to call even
* if {@link Utils#getContext()} is not available.
*/
public class Logger {
/**
@@ -17,99 +29,173 @@ public class Logger {
*/
@FunctionalInterface
public interface LogMessage {
/**
* @return Logger string message. This method is only called if logging is enabled.
*/
@NonNull
String buildMessageString();
}
/**
* @return For outer classes, this returns {@link Class#getSimpleName()}.
* For static, inner, or anonymous classes, this returns the simple name of the enclosing class.
* <br>
* For example, each of these classes return 'SomethingView':
* <code>
* com.company.SomethingView
* com.company.SomethingView$StaticClass
* com.company.SomethingView$1
* </code>
*/
private String findOuterClassSimpleName() {
var selfClass = this.getClass();
private enum LogLevel {
DEBUG,
INFO,
ERROR
}
String fullClassName = selfClass.getName();
final int dollarSignIndex = fullClassName.indexOf('$');
if (dollarSignIndex < 0) {
return selfClass.getSimpleName(); // Already an outer class.
/**
* Log tag prefix. Only used for system logging.
*/
private static final String REVANCED_LOG_TAG_PREFIX = "revanced: ";
private static final String LOGGER_CLASS_NAME = Logger.class.getName();
/**
* @return For outer classes, this returns {@link Class#getSimpleName()}.
* For static, inner, or anonymous classes, this returns the simple name of the enclosing class.
* <br>
* For example, each of these classes returns 'SomethingView':
* <code>
* com.company.SomethingView
* com.company.SomethingView$StaticClass
* com.company.SomethingView$1
* </code>
*/
private static String getOuterClassSimpleName(Object obj) {
Class<?> logClass = obj.getClass();
String fullClassName = logClass.getName();
final int dollarSignIndex = fullClassName.indexOf('$');
if (dollarSignIndex < 0) {
return logClass.getSimpleName(); // Already an outer class.
}
// Class is inner, static, or anonymous.
// Parse the simple name full name.
// A class with no package returns index of -1, but incrementing gives index zero which is correct.
final int simpleClassNameStartIndex = fullClassName.lastIndexOf('.') + 1;
return fullClassName.substring(simpleClassNameStartIndex, dollarSignIndex);
}
/**
* Internal method to handle logging to Android Log and {@link LogBufferManager}.
* Appends the log message, stack trace (if enabled), and exception (if present) to logBuffer
* with class name but without 'revanced:' prefix.
*
* @param logLevel The log level.
* @param message Log message object.
* @param ex Optional exception.
* @param includeStackTrace If the current stack should be included.
* @param showToast If a toast is to be shown.
*/
private static void logInternal(LogLevel logLevel, LogMessage message, @Nullable Throwable ex,
boolean includeStackTrace, boolean showToast) {
// It's very important that no Settings are used in this method,
// as this code is used when a context is not set and thus referencing
// a setting will crash the app.
String messageString = message.buildMessageString();
String className = getOuterClassSimpleName(message);
String logText = messageString;
// Append exception message if present.
if (ex != null) {
var exceptionMessage = ex.getMessage();
if (exceptionMessage != null) {
logText += "\nException: " + exceptionMessage;
}
}
// Class is inner, static, or anonymous.
// Parse the simple name full name.
// A class with no package returns index of -1, but incrementing gives index zero which is correct.
final int simpleClassNameStartIndex = fullClassName.lastIndexOf('.') + 1;
return fullClassName.substring(simpleClassNameStartIndex, dollarSignIndex);
if (includeStackTrace) {
var sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));
String stackTrace = sw.toString();
// Remove the stacktrace elements of this class.
final int loggerIndex = stackTrace.lastIndexOf(LOGGER_CLASS_NAME);
final int loggerBegins = stackTrace.indexOf('\n', loggerIndex);
logText += stackTrace.substring(loggerBegins);
}
// Do not include "revanced:" prefix in clipboard logs.
String managerToastString = className + ": " + logText;
LogBufferManager.appendToLogBuffer(managerToastString);
String logTag = REVANCED_LOG_TAG_PREFIX + className;
switch (logLevel) {
case DEBUG:
if (ex == null) Log.d(logTag, logText);
else Log.d(logTag, logText, ex);
break;
case INFO:
if (ex == null) Log.i(logTag, logText);
else Log.i(logTag, logText, ex);
break;
case ERROR:
if (ex == null) Log.e(logTag, logText);
else Log.e(logTag, logText, ex);
break;
}
if (showToast) {
Utils.showToastLong(managerToastString);
}
}
private static final String REVANCED_LOG_PREFIX = "revanced: ";
private static boolean shouldLogDebug() {
// If the app is still starting up and the context is not yet set,
// then allow debug logging regardless what the debug setting actually is.
return Utils.context == null || DEBUG.get();
}
private static boolean shouldShowErrorToast() {
return Utils.context != null && DEBUG_TOAST_ON_ERROR.get();
}
private static boolean includeStackTrace() {
return Utils.context != null && DEBUG_STACKTRACE.get();
}
/**
* Logs debug messages under the outer class name of the code calling this method.
* Whenever possible, the log string should be constructed entirely inside {@link LogMessage#buildMessageString()}
* so the performance cost of building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
* <p>
* Whenever possible, the log string should be constructed entirely inside
* {@link LogMessage#buildMessageString()} so the performance cost of
* building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
*/
public static void printDebug(@NonNull LogMessage message) {
public static void printDebug(LogMessage message) {
printDebug(message, null);
}
/**
* Logs debug messages under the outer class name of the code calling this method.
* Whenever possible, the log string should be constructed entirely inside {@link LogMessage#buildMessageString()}
* so the performance cost of building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
* <p>
* Whenever possible, the log string should be constructed entirely inside
* {@link LogMessage#buildMessageString()} so the performance cost of
* building strings is paid only if {@link BaseSettings#DEBUG} is enabled.
*/
public static void printDebug(@NonNull LogMessage message, @Nullable Exception ex) {
if (DEBUG.get()) {
String logMessage = message.buildMessageString();
String logTag = REVANCED_LOG_PREFIX + message.findOuterClassSimpleName();
if (DEBUG_STACKTRACE.get()) {
var builder = new StringBuilder(logMessage);
var sw = new StringWriter();
new Throwable().printStackTrace(new PrintWriter(sw));
builder.append('\n').append(sw);
logMessage = builder.toString();
}
if (ex == null) {
Log.d(logTag, logMessage);
} else {
Log.d(logTag, logMessage, ex);
}
public static void printDebug(LogMessage message, @Nullable Exception ex) {
if (shouldLogDebug()) {
logInternal(LogLevel.DEBUG, message, ex, includeStackTrace(), false);
}
}
/**
* Logs information messages using the outer class name of the code calling this method.
*/
public static void printInfo(@NonNull LogMessage message) {
public static void printInfo(LogMessage message) {
printInfo(message, null);
}
/**
* Logs information messages using the outer class name of the code calling this method.
*/
public static void printInfo(@NonNull LogMessage message, @Nullable Exception ex) {
String logTag = REVANCED_LOG_PREFIX + message.findOuterClassSimpleName();
String logMessage = message.buildMessageString();
if (ex == null) {
Log.i(logTag, logMessage);
} else {
Log.i(logTag, logMessage, ex);
}
public static void printInfo(LogMessage message, @Nullable Exception ex) {
logInternal(LogLevel.INFO, message, ex, includeStackTrace(), false);
}
/**
* Logs exceptions under the outer class name of the code calling this method.
* Appends the log message, exception (if present), and toast message (if enabled) to logBuffer.
*/
public static void printException(@NonNull LogMessage message) {
public static void printException(LogMessage message) {
printException(message, null);
}
@@ -122,35 +208,7 @@ public class Logger {
* @param message log message
* @param ex exception (optional)
*/
public static void printException(@NonNull LogMessage message, @Nullable Throwable ex) {
String messageString = message.buildMessageString();
String outerClassSimpleName = message.findOuterClassSimpleName();
String logMessage = REVANCED_LOG_PREFIX + outerClassSimpleName;
if (ex == null) {
Log.e(logMessage, messageString);
} else {
Log.e(logMessage, messageString, ex);
}
if (DEBUG_TOAST_ON_ERROR.get()) {
Utils.showToastLong(outerClassSimpleName + ": " + messageString);
}
public static void printException(LogMessage message, @Nullable Throwable ex) {
logInternal(LogLevel.ERROR, message, ex, includeStackTrace(), shouldShowErrorToast());
}
/**
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
* Normally this method should not be used.
*/
public static void initializationInfo(@NonNull Class<?> callingClass, @NonNull String message) {
Log.i(REVANCED_LOG_PREFIX + callingClass.getSimpleName(), message);
}
/**
* Logging to use if {@link BaseSettings#DEBUG} or {@link Utils#getContext()} may not be initialized.
* Normally this method should not be used.
*/
public static void initializationException(@NonNull Class<?> callingClass, @NonNull String message,
@Nullable Exception ex) {
Log.e(REVANCED_LOG_PREFIX + callingClass.getSimpleName(), message, ex);
}
}
}

View File

@@ -3,15 +3,21 @@ package app.revanced.extension.shared.checks;
import static android.text.Html.FROM_HTML_MODE_COMPACT;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.DialogFragmentOnStartAction;
import static app.revanced.extension.shared.Utils.dipToPixels;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.app.Dialog;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.net.Uri;
import android.text.Html;
import android.util.Pair;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
@@ -86,38 +92,58 @@ abstract class Check {
);
Utils.runOnMainThreadDelayed(() -> {
AlertDialog alert = new AlertDialog.Builder(activity)
.setCancelable(false)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle(str("revanced_check_environment_failed_title"))
.setMessage(message)
.setPositiveButton(
" ",
(dialog, which) -> {
final var intent = new Intent(Intent.ACTION_VIEW, GOOD_SOURCE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
// Create the custom dialog.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
activity,
str("revanced_check_environment_failed_title"), // Title.
message, // Message.
null, // No EditText.
str("revanced_check_environment_dialog_open_official_source_button"), // OK button text.
() -> {
// Action for the OK (website) button.
final var intent = new Intent(Intent.ACTION_VIEW, GOOD_SOURCE);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
// Shutdown to prevent the user from navigating back to this app,
// which is no longer showing a warning dialog.
activity.finishAffinity();
System.exit(0);
}
).setNegativeButton(
" ",
(dialog, which) -> {
// Cleanup data if the user incorrectly imported a huge negative number.
final int current = Math.max(0, BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get());
BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.save(current + 1);
// Shutdown to prevent the user from navigating back to this app,
// which is no longer showing a warning dialog.
activity.finishAffinity();
System.exit(0);
},
null, // No cancel button.
str("revanced_check_environment_dialog_ignore_button"), // Neutral button text.
() -> {
// Neutral button action.
// Cleanup data if the user incorrectly imported a huge negative number.
final int current = Math.max(0, BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.get());
BaseSettings.CHECK_ENVIRONMENT_WARNINGS_ISSUED.save(current + 1);
},
true // Dismiss dialog when onNeutralClick.
);
dialog.dismiss();
}
).create();
// Get the dialog and main layout.
Dialog dialog = dialogPair.first;
LinearLayout mainLayout = dialogPair.second;
Utils.showDialog(activity, alert, false, new DialogFragmentOnStartAction() {
// Add icon to the dialog.
ImageView iconView = new ImageView(activity);
iconView.setImageResource(Utils.getResourceIdentifier("revanced_ic_dialog_alert", "drawable"));
iconView.setColorFilter(Utils.getAppForegroundColor(), PorterDuff.Mode.SRC_IN);
iconView.setPadding(0, 0, 0, 0);
LinearLayout.LayoutParams iconParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
iconParams.gravity = Gravity.CENTER;
mainLayout.addView(iconView, 0); // Add icon at the top.
dialog.setCancelable(false);
// Show the dialog.
Utils.showDialog(activity, dialog, false, new DialogFragmentOnStartAction() {
boolean hasRun;
@Override
public void onStart(AlertDialog dialog) {
public void onStart(Dialog dialog) {
// Only run this once, otherwise if the user changes to a different app
// then changes back, this handler will run again and disable the buttons.
if (hasRun) {
@@ -125,19 +151,43 @@ abstract class Check {
}
hasRun = true;
var openWebsiteButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
// Get the button container to access buttons.
LinearLayout buttonContainer = (LinearLayout) mainLayout.getChildAt(mainLayout.getChildCount() - 1);
Button openWebsiteButton;
Button ignoreButton;
// Check if buttons are in a single-row layout (buttonContainer has one child: rowContainer).
if (buttonContainer.getChildCount() == 1 && buttonContainer.getChildAt(0) instanceof LinearLayout) {
LinearLayout rowContainer = (LinearLayout) buttonContainer.getChildAt(0);
// Neutral button is the first child (index 0).
ignoreButton = (Button) rowContainer.getChildAt(0);
// OK button is the last child.
openWebsiteButton = (Button) rowContainer.getChildAt(rowContainer.getChildCount() - 1);
} else {
// Multi-row layout: buttons are in separate containers, ordered OK, Cancel, Neutral.
LinearLayout okContainer =
(LinearLayout) buttonContainer.getChildAt(0); // OK is first.
openWebsiteButton = (Button) okContainer.getChildAt(0);
LinearLayout neutralContainer =
(LinearLayout)buttonContainer.getChildAt(buttonContainer.getChildCount() - 1); // Neutral is last.
ignoreButton = (Button) neutralContainer.getChildAt(0);
}
// Initially set buttons to INVISIBLE and disabled.
openWebsiteButton.setVisibility(View.INVISIBLE);
openWebsiteButton.setEnabled(false);
ignoreButton.setVisibility(View.INVISIBLE);
ignoreButton.setEnabled(false);
var dismissButton = dialog.getButton(DialogInterface.BUTTON_NEGATIVE);
dismissButton.setEnabled(false);
getCountdownRunnable(dismissButton, openWebsiteButton).run();
// Start the countdown for showing and enabling buttons.
getCountdownRunnable(ignoreButton, openWebsiteButton).run();
}
});
}, 1000); // Use a delay, so this dialog is shown on top of any other startup dialogs.
}
private static Runnable getCountdownRunnable(Button dismissButton, Button openWebsiteButton) {
private static Runnable getCountdownRunnable(Button ignoreButton, Button openWebsiteButton) {
return new Runnable() {
private int secondsRemaining = SECONDS_BEFORE_SHOWING_IGNORE_BUTTON;
@@ -146,17 +196,15 @@ abstract class Check {
Utils.verifyOnMainThread();
if (secondsRemaining > 0) {
if (secondsRemaining - SECONDS_BEFORE_SHOWING_WEBSITE_BUTTON == 0) {
openWebsiteButton.setText(str("revanced_check_environment_dialog_open_official_source_button"));
if (secondsRemaining - SECONDS_BEFORE_SHOWING_WEBSITE_BUTTON <= 0) {
openWebsiteButton.setVisibility(View.VISIBLE);
openWebsiteButton.setEnabled(true);
}
secondsRemaining--;
Utils.runOnMainThreadDelayed(this, 1000);
} else {
dismissButton.setText(str("revanced_check_environment_dialog_ignore_button"));
dismissButton.setEnabled(true);
ignoreButton.setVisibility(View.VISIBLE);
ignoreButton.setEnabled(true);
}
}
};

View File

@@ -52,7 +52,7 @@ public class Route {
private int countMatches(CharSequence seq, char c) {
int count = 0;
for (int i = 0; i < seq.length(); i++) {
for (int i = 0, length = seq.length(); i < length; i++) {
if (seq.charAt(i) == c)
count++;
}

View File

@@ -89,9 +89,11 @@ public enum AppLanguage {
ZU;
private final String language;
private final Locale locale;
AppLanguage() {
language = name().toLowerCase(Locale.US);
locale = Locale.forLanguageTag(language);
}
/**
@@ -112,6 +114,6 @@ public enum AppLanguage {
return Locale.getDefault();
}
return Locale.forLanguageTag(language);
return locale;
}
}

View File

@@ -71,15 +71,20 @@ public class EnumSetting<T extends Enum<?>> extends Setting<T> {
json.put(importExportKey, value.name().toLowerCase(Locale.ENGLISH));
}
@NonNull
private T getEnumFromString(String enumName) {
/**
* @param enumName Enum name. Casing does not matter.
* @return Enum of this type with the same declared name.
* @throws IllegalArgumentException if the name is not a valid enum of this type.
*/
protected T getEnumFromString(String enumName) {
//noinspection ConstantConditions
for (Enum<?> value : defaultValue.getClass().getEnumConstants()) {
if (value.name().equalsIgnoreCase(enumName)) {
// noinspection unchecked
//noinspection unchecked
return (T) value;
}
}
throw new IllegalArgumentException("Unknown enum value: " + enumName);
}
@@ -103,7 +108,9 @@ public class EnumSetting<T extends Enum<?>> extends Setting<T> {
* Availability based on if this setting is currently set to any of the provided types.
*/
@SafeVarargs
public final Setting.Availability availability(@NonNull T... types) {
public final Setting.Availability availability(T... types) {
Objects.requireNonNull(types);
return () -> {
T currentEnumType = get();
for (T enumType : types) {

View File

@@ -28,16 +28,14 @@ public abstract class Setting<T> {
/**
* Availability based on a single parent setting being enabled.
*/
@NonNull
public static Availability parent(@NonNull BooleanSetting parent) {
public static Availability parent(BooleanSetting parent) {
return parent::get;
}
/**
* Availability based on all parents being enabled.
*/
@NonNull
public static Availability parentsAll(@NonNull BooleanSetting... parents) {
public static Availability parentsAll(BooleanSetting... parents) {
return () -> {
for (BooleanSetting parent : parents) {
if (!parent.get()) return false;
@@ -49,8 +47,7 @@ public abstract class Setting<T> {
/**
* Availability based on any parent being enabled.
*/
@NonNull
public static Availability parentsAny(@NonNull BooleanSetting... parents) {
public static Availability parentsAny(BooleanSetting... parents) {
return () -> {
for (BooleanSetting parent : parents) {
if (parent.get()) return true;
@@ -79,7 +76,7 @@ public abstract class Setting<T> {
/**
* Adds a callback for {@link #importFromJSON(Context, String)} and {@link #exportToJson(Context)}.
*/
public static void addImportExportCallback(@NonNull ImportExportCallback callback) {
public static void addImportExportCallback(ImportExportCallback callback) {
importExportCallbacks.add(Objects.requireNonNull(callback));
}
@@ -100,14 +97,13 @@ public abstract class Setting<T> {
public static final SharedPrefCategory preferences = new SharedPrefCategory("revanced_prefs");
@Nullable
public static Setting<?> getSettingFromPath(@NonNull String str) {
public static Setting<?> getSettingFromPath(String str) {
return PATH_TO_SETTINGS.get(str);
}
/**
* @return All settings that have been created.
*/
@NonNull
public static List<Setting<?>> allLoadedSettings() {
return Collections.unmodifiableList(SETTINGS);
}
@@ -115,7 +111,6 @@ public abstract class Setting<T> {
/**
* @return All settings that have been created, sorted by keys.
*/
@NonNull
private static List<Setting<?>> allLoadedSettingsSorted() {
Collections.sort(SETTINGS, (Setting<?> o1, Setting<?> o2) -> o1.key.compareTo(o2.key));
return allLoadedSettings();
@@ -124,13 +119,11 @@ public abstract class Setting<T> {
/**
* The key used to store the value in the shared preferences.
*/
@NonNull
public final String key;
/**
* The default value of the setting.
*/
@NonNull
public final T defaultValue;
/**
@@ -161,7 +154,6 @@ public abstract class Setting<T> {
/**
* The value of the setting.
*/
@NonNull
protected volatile T value;
public Setting(String key, T defaultValue) {
@@ -199,8 +191,8 @@ public abstract class Setting<T> {
* @param userDialogMessage Confirmation message to display, if the user tries to change the setting from the default value.
* @param availability Condition that must be true, for this setting to be available to configure.
*/
public Setting(@NonNull String key,
@NonNull T defaultValue,
public Setting(String key,
T defaultValue,
boolean rebootApp,
boolean includeWithImportExport,
@Nullable String userDialogMessage,
@@ -227,7 +219,7 @@ public abstract class Setting<T> {
/**
* Migrate a setting value if the path is renamed but otherwise the old and new settings are identical.
*/
public static <T> void migrateOldSettingToNew(@NonNull Setting<T> oldSetting, @NonNull Setting<T> newSetting) {
public static <T> void migrateOldSettingToNew(Setting<T> oldSetting, Setting<T> newSetting) {
if (oldSetting == newSetting) throw new IllegalArgumentException();
if (!oldSetting.isSetToDefault()) {
@@ -243,7 +235,7 @@ public abstract class Setting<T> {
* This method will be deleted in the future.
*/
@SuppressWarnings("rawtypes")
public static void migrateFromOldPreferences(@NonNull SharedPrefCategory oldPrefs, @NonNull Setting setting, String settingKey) {
public static void migrateFromOldPreferences(SharedPrefCategory oldPrefs, Setting setting, String settingKey) {
if (!oldPrefs.preferences.contains(settingKey)) {
return; // Nothing to do.
}
@@ -285,7 +277,7 @@ public abstract class Setting<T> {
* This intentionally is a static method to deter
* accidental usage when {@link #save(Object)} was intended.
*/
public static void privateSetValueFromString(@NonNull Setting<?> setting, @NonNull String newValue) {
public static void privateSetValueFromString(Setting<?> setting, String newValue) {
setting.setValueFromString(newValue);
// Clear the preference value since default is used, to allow changing
@@ -299,7 +291,7 @@ public abstract class Setting<T> {
/**
* Sets the value of {@link #value}, but do not save to {@link #preferences}.
*/
protected abstract void setValueFromString(@NonNull String newValue);
protected abstract void setValueFromString(String newValue);
/**
* Load and set the value of {@link #value}.
@@ -309,7 +301,7 @@ public abstract class Setting<T> {
/**
* Persistently saves the value.
*/
public final void save(@NonNull T newValue) {
public final void save(T newValue) {
if (value.equals(newValue)) {
return;
}
@@ -342,9 +334,12 @@ public abstract class Setting<T> {
/**
* Identical to calling {@link #save(Object)} using {@link #defaultValue}.
*
* @return The newly saved default value.
*/
public void resetToDefault() {
public T resetToDefault() {
save(defaultValue);
return defaultValue;
}
/**
@@ -403,7 +398,6 @@ public abstract class Setting<T> {
json.put(importExportKey, value);
}
@NonNull
public static String exportToJson(@Nullable Context alertDialogContext) {
try {
JSONObject json = new JSONObject();
@@ -442,7 +436,7 @@ public abstract class Setting<T> {
/**
* @return if any settings that require a reboot were changed.
*/
public static boolean importFromJSON(@NonNull Context alertDialogContext, @NonNull String settingsJsonString) {
public static boolean importFromJSON(Context alertDialogContext, String settingsJsonString) {
try {
if (!settingsJsonString.matches("[\\s\\S]*\\{")) {
settingsJsonString = '{' + settingsJsonString + '}'; // Restore outer JSON braces

View File

@@ -3,12 +3,20 @@ package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.*;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.preference.SwitchPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.util.Pair;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -44,7 +52,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
* Set by subclasses if Strings cannot be added as a resource.
*/
@Nullable
protected static String restartDialogButtonText, restartDialogTitle, confirmDialogTitle;
protected static String restartDialogButtonText, restartDialogTitle, confirmDialogTitle, restartDialogMessage;
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
try {
@@ -76,7 +84,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
updatingPreference = true;
// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
// Updating here can can cause a recursive call back into this same method.
// Updating here can cause a recursive call back into this same method.
updatePreference(pref, setting, true, settingImportInProgress);
// Update any other preference availability that may now be different.
updateUIAvailability();
@@ -116,11 +124,14 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
showingUserDialogMessage = true;
new AlertDialog.Builder(context)
.setTitle(confirmDialogTitle)
.setMessage(Objects.requireNonNull(setting.userDialogMessage).toString())
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
// User confirmed, save to the Setting.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
context,
confirmDialogTitle, // Title.
Objects.requireNonNull(setting.userDialogMessage).toString(), // No message.
null, // No EditText.
null, // OK button text.
() -> {
// OK button action. User confirmed, save to the Setting.
updatePreference(pref, setting, true, false);
// Update availability of other preferences that may be changed.
@@ -129,23 +140,27 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
if (setting.rebootApp) {
showRestartDialog(context);
}
})
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {
// Restore whatever the setting was before the change.
},
() -> {
// Cancel button action. Restore whatever the setting was before the change.
updatePreference(pref, setting, true, true);
})
.setOnDismissListener(dialog -> {
showingUserDialogMessage = false;
})
.setCancelable(false)
.show();
},
null, // No Neutral button.
null, // No Neutral button action.
true // Dismiss dialog when onNeutralClick.
);
dialogPair.first.setOnDismissListener(d -> showingUserDialogMessage = false);
// Show the dialog.
dialogPair.first.show();
}
/**
* Updates all Preferences values and their availability using the current values in {@link Setting}.
*/
protected void updateUIToSettingValues() {
updatePreferenceScreen(getPreferenceScreen(), true,true);
updatePreferenceScreen(getPreferenceScreen(), true, true);
}
/**
@@ -280,17 +295,27 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
if (restartDialogTitle == null) {
restartDialogTitle = str("revanced_settings_restart_title");
}
if (restartDialogMessage == null) {
restartDialogMessage = str("revanced_settings_restart_dialog_message");
}
if (restartDialogButtonText == null) {
restartDialogButtonText = str("revanced_settings_restart");
}
new AlertDialog.Builder(context)
.setMessage(restartDialogTitle)
.setPositiveButton(restartDialogButtonText, (dialog, id)
-> Utils.restartApp(context))
.setNegativeButton(android.R.string.cancel, null)
.setCancelable(false)
.show();
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(context,
restartDialogTitle, // Title.
restartDialogMessage, // Message.
null, // No EditText.
restartDialogButtonText, // OK button text.
() -> Utils.restartApp(context), // OK button action.
() -> {}, // Cancel button action (dismiss only).
null, // No Neutral button text.
null, // No Neutral button action.
true // Dismiss dialog when onNeutralClick.
);
// Show the dialog.
dialogPair.first.show();
}
@SuppressLint("ResourceType")

View File

@@ -0,0 +1,449 @@
package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import static app.revanced.extension.shared.Utils.dipToPixels;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.text.Editable;
import android.text.InputType;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.widget.*;
import androidx.annotation.ColorInt;
import java.util.Locale;
import java.util.regex.Pattern;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.settings.StringSetting;
/**
* A custom preference for selecting a color via a hexadecimal code or a color picker dialog.
* Extends {@link EditTextPreference} to display a colored dot in the widget area,
* reflecting the currently selected color. The dot is dimmed when the preference is disabled.
*/
@SuppressWarnings({"unused", "deprecation"})
public class ColorPickerPreference extends EditTextPreference {
/**
* Character to show the color appearance.
*/
public static final String COLOR_DOT_STRING = "";
/**
* Length of a valid color string of format #RRGGBB.
*/
public static final int COLOR_STRING_LENGTH = 7;
/**
* Matches everything that is not a hex number/letter.
*/
private static final Pattern PATTERN_NOT_HEX = Pattern.compile("[^0-9A-Fa-f]");
/**
* Alpha for dimming when the preference is disabled.
*/
private static final float DISABLED_ALPHA = 0.5f; // 50%
/**
* View displaying a colored dot in the widget area.
*/
private View widgetColorDot;
/**
* Current color in RGB format (without alpha).
*/
@ColorInt
private int currentColor;
/**
* Associated setting for storing the color value.
*/
private StringSetting colorSetting;
/**
* Dialog TextWatcher for the EditText to monitor color input changes.
*/
private TextWatcher colorTextWatcher;
/**
* Dialog TextView displaying a colored dot for the selected color preview in the dialog.
*/
private TextView dialogColorPreview;
/**
* Dialog color picker view.
*/
private ColorPickerView dialogColorPickerView;
/**
* Removes non valid hex characters, converts to all uppercase,
* and adds # character to the start if not present.
*/
public static String cleanupColorCodeString(String colorString) {
// Remove non-hex chars, convert to uppercase, and ensure correct length
String result = "#" + PATTERN_NOT_HEX.matcher(colorString)
.replaceAll("").toUpperCase(Locale.ROOT);
if (result.length() < COLOR_STRING_LENGTH) {
return result;
}
return result.substring(0, COLOR_STRING_LENGTH);
}
/**
* @param color RGB color, without an alpha channel.
* @return #RRGGBB hex color string
*/
public static String getColorString(@ColorInt int color) {
String colorString = String.format("#%06X", color);
if ((color & 0xFF000000) != 0) {
// Likely a bug somewhere.
Logger.printException(() -> "getColorString: color has alpha channel: " + colorString);
}
return colorString;
}
/**
* Creates a Spanned object for a colored dot using SpannableString.
*
* @param color The RGB color (without alpha).
* @return A Spanned object with the colored dot.
*/
public static Spanned getColorDot(@ColorInt int color) {
SpannableString spannable = new SpannableString(COLOR_DOT_STRING);
spannable.setSpan(new ForegroundColorSpan(color | 0xFF000000), 0, COLOR_DOT_STRING.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spannable.setSpan(new RelativeSizeSpan(1.5f), 0, 1,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}
public ColorPickerPreference(Context context) {
super(context);
init();
}
public ColorPickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ColorPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
/**
* Initializes the preference by setting up the EditText, loading the color, and set the widget layout.
*/
private void init() {
colorSetting = (StringSetting) Setting.getSettingFromPath(getKey());
if (colorSetting == null) {
Logger.printException(() -> "Could not find color setting for: " + getKey());
}
EditText editText = getEditText();
editText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS
| InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
editText.setAutofillHints((String) null);
}
// Set the widget layout to a custom layout containing the colored dot.
setWidgetLayoutResource(getResourceIdentifier("revanced_color_dot_widget", "layout"));
}
/**
* Sets the selected color and updates the UI and settings.
*
* @param colorString The color in hexadecimal format (e.g., "#RRGGBB").
* @throws IllegalArgumentException If the color string is invalid.
*/
@Override
public final void setText(String colorString) {
try {
Logger.printDebug(() -> "setText: " + colorString);
super.setText(colorString);
currentColor = Color.parseColor(colorString) & 0x00FFFFFF;
if (colorSetting != null) {
colorSetting.save(getColorString(currentColor));
}
updateColorPreview();
updateWidgetColorDot();
} catch (IllegalArgumentException ex) {
// This code is reached if the user pastes settings json with an invalid color
// since this preference is updated with the new setting text.
Logger.printDebug(() -> "Parse color error: " + colorString, ex);
Utils.showToastShort(str("revanced_settings_color_invalid"));
setText(colorSetting.resetToDefault());
} catch (Exception ex) {
Logger.printException(() -> "setText failure: " + colorString, ex);
}
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
widgetColorDot = view.findViewById(getResourceIdentifier(
"revanced_color_dot_widget", "id"));
widgetColorDot.setBackgroundResource(getResourceIdentifier(
"revanced_settings_circle_background", "drawable"));
widgetColorDot.getBackground().setTint(currentColor | 0xFF000000);
widgetColorDot.setAlpha(isEnabled() ? 1.0f : DISABLED_ALPHA);
}
/**
* Updates the color preview TextView with a colored dot.
*/
private void updateColorPreview() {
if (dialogColorPreview != null) {
dialogColorPreview.setText(getColorDot(currentColor));
}
}
private void updateWidgetColorDot() {
if (widgetColorDot != null) {
widgetColorDot.getBackground().setTint(currentColor | 0xFF000000);
widgetColorDot.setAlpha(isEnabled() ? 1.0f : DISABLED_ALPHA);
}
}
/**
* Creates a TextWatcher to monitor changes in the EditText for color input.
*
* @return A TextWatcher that updates the color preview on valid input.
*/
private TextWatcher createColorTextWatcher(ColorPickerView colorPickerView) {
return new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable edit) {
try {
String colorString = edit.toString();
String sanitizedColorString = cleanupColorCodeString(colorString);
if (!sanitizedColorString.equals(colorString)) {
edit.replace(0, colorString.length(), sanitizedColorString);
return;
}
if (sanitizedColorString.length() != COLOR_STRING_LENGTH) {
// User is still typing out the color.
return;
}
final int newColor = Color.parseColor(colorString);
if (currentColor != newColor) {
Logger.printDebug(() -> "afterTextChanged: " + sanitizedColorString);
currentColor = newColor;
updateColorPreview();
updateWidgetColorDot();
colorPickerView.setColor(newColor);
}
} catch (Exception ex) {
// Should never be reached since input is validated before using.
Logger.printException(() -> "afterTextChanged failure", ex);
}
}
};
}
/**
* Creates a Dialog with a color preview and EditText for hex color input.
*/
@Override
protected void showDialog(Bundle state) {
Context context = getContext();
// Inflate color picker view.
View colorPicker = LayoutInflater.from(context).inflate(
getResourceIdentifier("revanced_color_picker", "layout"), null);
dialogColorPickerView = colorPicker.findViewById(
getResourceIdentifier("revanced_color_picker_view", "id"));
dialogColorPickerView.setColor(currentColor);
// Horizontal layout for preview and EditText.
LinearLayout inputLayout = new LinearLayout(context);
inputLayout.setOrientation(LinearLayout.HORIZONTAL);
dialogColorPreview = new TextView(context);
LinearLayout.LayoutParams previewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
previewParams.setMargins(dipToPixels(15), 0, dipToPixels(10), 0); // text dot has its own indents so 15, instead 16.
dialogColorPreview.setLayoutParams(previewParams);
inputLayout.addView(dialogColorPreview);
updateColorPreview();
EditText editText = getEditText();
ViewParent parent = editText.getParent();
if (parent instanceof ViewGroup parentViewGroup) {
parentViewGroup.removeView(editText);
}
editText.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
));
String currentColorString = getColorString(currentColor);
editText.setText(currentColorString);
editText.setSelection(currentColorString.length());
editText.setTypeface(Typeface.MONOSPACE);
colorTextWatcher = createColorTextWatcher(dialogColorPickerView);
editText.addTextChangedListener(colorTextWatcher);
inputLayout.addView(editText);
// Add a dummy view to take up remaining horizontal space,
// otherwise it will show an oversize underlined text view.
View paddingView = new View(context);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
0,
LinearLayout.LayoutParams.MATCH_PARENT,
1f
);
paddingView.setLayoutParams(params);
inputLayout.addView(paddingView);
// Create content container for color picker and input layout.
LinearLayout contentContainer = new LinearLayout(context);
contentContainer.setOrientation(LinearLayout.VERTICAL);
contentContainer.addView(colorPicker);
contentContainer.addView(inputLayout);
// Create ScrollView to wrap the content container.
ScrollView contentScrollView = new ScrollView(context);
contentScrollView.setVerticalScrollBarEnabled(false); // Disable vertical scrollbar.
contentScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER); // Disable overscroll effect.
LinearLayout.LayoutParams scrollViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
0,
1.0f
);
contentScrollView.setLayoutParams(scrollViewParams);
contentScrollView.addView(contentContainer);
// Create custom dialog.
final int originalColor = currentColor & 0x00FFFFFF;
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
context,
getTitle() != null ? getTitle().toString() : str("revanced_settings_color_picker_title"), // Title.
null, // No message.
null, // No EditText.
null, // OK button text.
() -> {
// OK button action.
try {
String colorString = editText.getText().toString();
if (colorString.length() != COLOR_STRING_LENGTH) {
Utils.showToastShort(str("revanced_settings_color_invalid"));
setText(getColorString(originalColor));
return;
}
setText(colorString);
} catch (Exception ex) {
// Should never happen due to a bad color string,
// since the text is validated and fixed while the user types.
Logger.printException(() -> "OK button failure", ex);
}
},
() -> {
// Cancel button action.
try {
// Restore the original color.
setText(getColorString(originalColor));
} catch (Exception ex) {
Logger.printException(() -> "Cancel button failure", ex);
}
},
str("revanced_settings_reset_color"), // Neutral button text.
() -> {
// Neutral button action.
try {
final int defaultColor = Color.parseColor(colorSetting.defaultValue) & 0x00FFFFFF;
// Setting view color causes listener callback into this class.
dialogColorPickerView.setColor(defaultColor);
} catch (Exception ex) {
Logger.printException(() -> "Reset button failure", ex);
}
},
false // Do not dismiss dialog when onNeutralClick.
);
// Add the ScrollView to the dialog's main layout.
LinearLayout dialogMainLayout = dialogPair.second;
dialogMainLayout.addView(contentScrollView, dialogMainLayout.getChildCount() - 1);
// Set up color picker listener with debouncing.
// Add listener last to prevent callbacks from set calls above.
dialogColorPickerView.setOnColorChangedListener(color -> {
// Check if it actually changed, since this callback
// can be caused by updates in afterTextChanged().
if (currentColor == color) {
return;
}
String updatedColorString = getColorString(color);
Logger.printDebug(() -> "onColorChanged: " + updatedColorString);
currentColor = color;
editText.setText(updatedColorString);
editText.setSelection(updatedColorString.length());
updateColorPreview();
updateWidgetColorDot();
});
// Configure and show the dialog.
Dialog dialog = dialogPair.first;
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
@Override
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (colorTextWatcher != null) {
getEditText().removeTextChangedListener(colorTextWatcher);
colorTextWatcher = null;
}
dialogColorPreview = null;
dialogColorPickerView = null;
}
@Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
updateWidgetColorDot();
}
}

View File

@@ -0,0 +1,500 @@
package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.Utils.dipToPixels;
import static app.revanced.extension.shared.settings.preference.ColorPickerPreference.getColorString;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposeShader;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.ColorInt;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
/**
* A custom color picker view that allows the user to select a color using a hue slider and a saturation-value selector.
* This implementation is density-independent and responsive across different screen sizes and DPIs.
*
* <p>
* This view displays two main components for color selection:
* <ul>
* <li><b>Hue Bar:</b> A horizontal bar at the bottom that allows the user to select the hue component of the color.
* <li><b>Saturation-Value Selector:</b> A rectangular area above the hue bar that allows the user to select the saturation and value (brightness)
* components of the color based on the selected hue.
* </ul>
*
* <p>
* The view uses {@link LinearGradient} and {@link ComposeShader} to create the color gradients for the hue bar and the
* saturation-value selector. It also uses {@link Paint} to draw the selectors (draggable handles).
*
* <p>
* The selected color can be retrieved using {@link #getColor()} and can be set using {@link #setColor(int)}.
* An {@link OnColorChangedListener} can be registered to receive notifications when the selected color changes.
*/
public class ColorPickerView extends View {
/**
* Interface definition for a callback to be invoked when the selected color changes.
*/
public interface OnColorChangedListener {
/**
* Called when the selected color has changed.
*
* Important: Callback color uses RGB format with zero alpha channel.
*
* @param color The new selected color.
*/
void onColorChanged(@ColorInt int color);
}
/** Expanded touch area for the hue bar to increase the touch-sensitive area. */
public static final float TOUCH_EXPANSION = dipToPixels(20f);
private static final float MARGIN_BETWEEN_AREAS = dipToPixels(24);
private static final float VIEW_PADDING = dipToPixels(16);
private static final float HUE_BAR_HEIGHT = dipToPixels(12);
private static final float HUE_CORNER_RADIUS = dipToPixels(6);
private static final float SELECTOR_RADIUS = dipToPixels(12);
private static final float SELECTOR_STROKE_WIDTH = 8;
/**
* Hue fill radius. Use slightly smaller radius for the selector handle fill,
* otherwise the anti-aliasing causes the fill color to bleed past the selector outline.
*/
private static final float SELECTOR_FILL_RADIUS = SELECTOR_RADIUS - SELECTOR_STROKE_WIDTH / 2;
/** Thin dark outline stroke width for the selector rings. */
private static final float SELECTOR_EDGE_STROKE_WIDTH = 1;
public static final float SELECTOR_EDGE_RADIUS =
SELECTOR_RADIUS + SELECTOR_STROKE_WIDTH / 2 + SELECTOR_EDGE_STROKE_WIDTH / 2;
/** Selector outline inner color. */
@ColorInt
private static final int SELECTOR_OUTLINE_COLOR = Color.WHITE;
/** Dark edge color for the selector rings. */
@ColorInt
private static final int SELECTOR_EDGE_COLOR = Color.parseColor("#CFCFCF");
private static final int[] HUE_COLORS = new int[361];
static {
for (int i = 0; i < 361; i++) {
HUE_COLORS[i] = Color.HSVToColor(new float[]{i, 1, 1});
}
}
/** Hue bar. */
private final Paint huePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/** Saturation-value selector. */
private final Paint saturationValuePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
/** Draggable selector. */
private final Paint selectorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
{
selectorPaint.setStrokeWidth(SELECTOR_STROKE_WIDTH);
}
/** Bounds of the hue bar. */
private final RectF hueRect = new RectF();
/** Bounds of the saturation-value selector. */
private final RectF saturationValueRect = new RectF();
/** HSV color calculations to avoid allocations during drawing. */
private final float[] hsvArray = {1, 1, 1};
/** Current hue value (0-360). */
private float hue = 0f;
/** Current saturation value (0-1). */
private float saturation = 1f;
/** Current value (brightness) value (0-1). */
private float value = 1f;
/** The currently selected color in RGB format with no alpha channel. */
@ColorInt
private int selectedColor;
private OnColorChangedListener colorChangedListener;
/** Track if we're currently dragging the hue or saturation handle. */
private boolean isDraggingHue;
private boolean isDraggingSaturation;
public ColorPickerView(Context context) {
super(context);
}
public ColorPickerView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final float DESIRED_ASPECT_RATIO = 0.8f; // height = width * 0.8
final int minWidth = Utils.dipToPixels(250);
final int minHeight = (int) (minWidth * DESIRED_ASPECT_RATIO) + (int) (HUE_BAR_HEIGHT + MARGIN_BETWEEN_AREAS);
int width = resolveSize(minWidth, widthMeasureSpec);
int height = resolveSize(minHeight, heightMeasureSpec);
// Ensure minimum dimensions for usability.
width = Math.max(width, minWidth);
height = Math.max(height, minHeight);
// Adjust height to maintain desired aspect ratio if possible.
final int desiredHeight = (int) (width * DESIRED_ASPECT_RATIO) + (int) (HUE_BAR_HEIGHT + MARGIN_BETWEEN_AREAS);
if (MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY) {
height = desiredHeight;
}
setMeasuredDimension(width, height);
}
/**
* Called when the size of the view changes.
* This method calculates and sets the bounds of the hue bar and saturation-value selector.
* It also creates the necessary shaders for the gradients.
*/
@Override
protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
super.onSizeChanged(width, height, oldWidth, oldHeight);
// Calculate bounds with hue bar at the bottom.
final float effectiveWidth = width - (2 * VIEW_PADDING);
final float effectiveHeight = height - (2 * VIEW_PADDING) - HUE_BAR_HEIGHT - MARGIN_BETWEEN_AREAS;
// Adjust rectangles to account for padding and density-independent dimensions.
saturationValueRect.set(
VIEW_PADDING,
VIEW_PADDING,
VIEW_PADDING + effectiveWidth,
VIEW_PADDING + effectiveHeight
);
hueRect.set(
VIEW_PADDING,
height - VIEW_PADDING - HUE_BAR_HEIGHT,
VIEW_PADDING + effectiveWidth,
height - VIEW_PADDING
);
// Update the shaders.
updateHueShader();
updateSaturationValueShader();
}
/**
* Updates the hue full spectrum (0-360 degrees).
*/
private void updateHueShader() {
LinearGradient hueShader = new LinearGradient(
hueRect.left, hueRect.top,
hueRect.right, hueRect.top,
HUE_COLORS,
null,
Shader.TileMode.CLAMP
);
huePaint.setShader(hueShader);
}
/**
* Updates the shader for the saturation-value selector based on the currently selected hue.
* This method creates a combined shader that blends a saturation gradient with a value gradient.
*/
private void updateSaturationValueShader() {
// Create a saturation-value gradient based on the current hue.
// Calculate the start color (white with the selected hue) for the saturation gradient.
final int startColor = Color.HSVToColor(new float[]{hue, 0f, 1f});
// Calculate the middle color (fully saturated color with the selected hue) for the saturation gradient.
final int midColor = Color.HSVToColor(new float[]{hue, 1f, 1f});
// Create a linear gradient for the saturation from startColor to midColor (horizontal).
LinearGradient satShader = new LinearGradient(
saturationValueRect.left, saturationValueRect.top,
saturationValueRect.right, saturationValueRect.top,
startColor,
midColor,
Shader.TileMode.CLAMP
);
// Create a linear gradient for the value (brightness) from white to black (vertical).
//noinspection ExtractMethodRecommender
LinearGradient valShader = new LinearGradient(
saturationValueRect.left, saturationValueRect.top,
saturationValueRect.left, saturationValueRect.bottom,
Color.WHITE,
Color.BLACK,
Shader.TileMode.CLAMP
);
// Combine the saturation and value shaders using PorterDuff.Mode.MULTIPLY to create the final color.
ComposeShader combinedShader = new ComposeShader(satShader, valShader, PorterDuff.Mode.MULTIPLY);
// Set the combined shader for the saturation-value paint.
saturationValuePaint.setShader(combinedShader);
}
/**
* Draws the color picker view on the canvas.
* This method draws the saturation-value selector, the hue bar with rounded corners,
* and the draggable handles.
*
* @param canvas The canvas on which to draw.
*/
@Override
protected void onDraw(Canvas canvas) {
// Draw the saturation-value selector rectangle.
canvas.drawRect(saturationValueRect, saturationValuePaint);
// Draw the hue bar.
canvas.drawRoundRect(hueRect, HUE_CORNER_RADIUS, HUE_CORNER_RADIUS, huePaint);
final float hueSelectorX = hueRect.left + (hue / 360f) * hueRect.width();
final float hueSelectorY = hueRect.centerY();
final float satSelectorX = saturationValueRect.left + saturation * saturationValueRect.width();
final float satSelectorY = saturationValueRect.top + (1 - value) * saturationValueRect.height();
// Draw the saturation and hue selector handle filled with the selected color.
hsvArray[0] = hue;
final int hueHandleColor = Color.HSVToColor(0xFF, hsvArray);
selectorPaint.setStyle(Paint.Style.FILL_AND_STROKE);
selectorPaint.setColor(hueHandleColor);
canvas.drawCircle(hueSelectorX, hueSelectorY, SELECTOR_FILL_RADIUS, selectorPaint);
selectorPaint.setColor(selectedColor | 0xFF000000);
canvas.drawCircle(satSelectorX, satSelectorY, SELECTOR_FILL_RADIUS, selectorPaint);
// Draw white outlines for the handles.
selectorPaint.setColor(SELECTOR_OUTLINE_COLOR);
selectorPaint.setStyle(Paint.Style.STROKE);
selectorPaint.setStrokeWidth(SELECTOR_STROKE_WIDTH);
canvas.drawCircle(hueSelectorX, hueSelectorY, SELECTOR_RADIUS, selectorPaint);
canvas.drawCircle(satSelectorX, satSelectorY, SELECTOR_RADIUS, selectorPaint);
// Draw thin dark outlines for the handles at the outer edge of the white outline.
selectorPaint.setColor(SELECTOR_EDGE_COLOR);
selectorPaint.setStrokeWidth(SELECTOR_EDGE_STROKE_WIDTH);
canvas.drawCircle(hueSelectorX, hueSelectorY, SELECTOR_EDGE_RADIUS, selectorPaint);
canvas.drawCircle(satSelectorX, satSelectorY, SELECTOR_EDGE_RADIUS, selectorPaint);
}
/**
* Handles touch events on the view.
* This method determines whether the touch event occurred within the hue bar or the saturation-value selector,
* updates the corresponding values (hue, saturation, value), and invalidates the view to trigger a redraw.
* <p>
* In addition to testing if the touch is within the strict rectangles, an expanded hit area (by selectorRadius)
* is used so that the draggable handles remain active even when half of the handle is outside the drawn bounds.
*
* @param event The motion event.
* @return True if the event was handled, false otherwise.
*/
@SuppressLint("ClickableViewAccessibility") // performClick is not overridden, but not needed in this case.
@Override
public boolean onTouchEvent(MotionEvent event) {
try {
final float x = event.getX();
final float y = event.getY();
final int action = event.getAction();
Logger.printDebug(() -> "onTouchEvent action: " + action + " x: " + x + " y: " + y);
// Define touch expansion for the hue bar.
RectF expandedHueRect = new RectF(
hueRect.left,
hueRect.top - TOUCH_EXPANSION,
hueRect.right,
hueRect.bottom + TOUCH_EXPANSION
);
switch (action) {
case MotionEvent.ACTION_DOWN:
// Calculate current handle positions.
final float hueSelectorX = hueRect.left + (hue / 360f) * hueRect.width();
final float hueSelectorY = hueRect.centerY();
final float satSelectorX = saturationValueRect.left + saturation * saturationValueRect.width();
final float valSelectorY = saturationValueRect.top + (1 - value) * saturationValueRect.height();
// Create hit areas for both handles.
RectF hueHitRect = new RectF(
hueSelectorX - SELECTOR_RADIUS,
hueSelectorY - SELECTOR_RADIUS,
hueSelectorX + SELECTOR_RADIUS,
hueSelectorY + SELECTOR_RADIUS
);
RectF satValHitRect = new RectF(
satSelectorX - SELECTOR_RADIUS,
valSelectorY - SELECTOR_RADIUS,
satSelectorX + SELECTOR_RADIUS,
valSelectorY + SELECTOR_RADIUS
);
// Check if the touch started on a handle or within the expanded hue bar area.
if (hueHitRect.contains(x, y)) {
isDraggingHue = true;
updateHueFromTouch(x);
} else if (satValHitRect.contains(x, y)) {
isDraggingSaturation = true;
updateSaturationValueFromTouch(x, y);
} else if (expandedHueRect.contains(x, y)) {
// Handle touch within the expanded hue bar area.
isDraggingHue = true;
updateHueFromTouch(x);
} else if (saturationValueRect.contains(x, y)) {
isDraggingSaturation = true;
updateSaturationValueFromTouch(x, y);
}
break;
case MotionEvent.ACTION_MOVE:
// Continue updating values even if touch moves outside the view.
if (isDraggingHue) {
updateHueFromTouch(x);
} else if (isDraggingSaturation) {
updateSaturationValueFromTouch(x, y);
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
isDraggingHue = false;
isDraggingSaturation = false;
break;
}
} catch (Exception ex) {
Logger.printException(() -> "onTouchEvent failure", ex);
}
return true;
}
/**
* Updates the hue value based on touch position, clamping to valid range.
*
* @param x The x-coordinate of the touch position.
*/
private void updateHueFromTouch(float x) {
// Clamp x to the hue rectangle bounds.
final float clampedX = Utils.clamp(x, hueRect.left, hueRect.right);
final float updatedHue = ((clampedX - hueRect.left) / hueRect.width()) * 360f;
if (hue == updatedHue) {
return;
}
hue = updatedHue;
updateSaturationValueShader();
updateSelectedColor();
}
/**
* Updates saturation and value based on touch position, clamping to valid range.
*
* @param x The x-coordinate of the touch position.
* @param y The y-coordinate of the touch position.
*/
private void updateSaturationValueFromTouch(float x, float y) {
// Clamp x and y to the saturation-value rectangle bounds.
final float clampedX = Utils.clamp(x, saturationValueRect.left, saturationValueRect.right);
final float clampedY = Utils.clamp(y, saturationValueRect.top, saturationValueRect.bottom);
final float updatedSaturation = (clampedX - saturationValueRect.left) / saturationValueRect.width();
final float updatedValue = 1 - ((clampedY - saturationValueRect.top) / saturationValueRect.height());
if (saturation == updatedSaturation && value == updatedValue) {
return;
}
saturation = updatedSaturation;
value = updatedValue;
updateSelectedColor();
}
/**
* Updates the selected color and notifies listeners.
*/
private void updateSelectedColor() {
final int updatedColor = Color.HSVToColor(0, new float[]{hue, saturation, value});
if (selectedColor != updatedColor) {
selectedColor = updatedColor;
if (colorChangedListener != null) {
colorChangedListener.onColorChanged(updatedColor);
}
}
// Must always redraw, otherwise if saturation is pure grey or black
// then the hue slider cannot be changed.
invalidate();
}
/**
* Sets the currently selected color.
*
* @param color The color to set in either ARGB or RGB format.
*/
public void setColor(@ColorInt int color) {
color &= 0x00FFFFFF;
if (selectedColor == color) {
return;
}
// Update the selected color.
selectedColor = color;
Logger.printDebug(() -> "setColor: " + getColorString(selectedColor));
// Convert the ARGB color to HSV values.
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
// Update the hue, saturation, and value.
hue = hsv[0];
saturation = hsv[1];
value = hsv[2];
// Update the saturation-value shader based on the new hue.
updateSaturationValueShader();
// Notify the listener if it's set.
if (colorChangedListener != null) {
colorChangedListener.onColorChanged(selectedColor);
}
// Invalidate the view to trigger a redraw.
invalidate();
}
/**
* Gets the currently selected color.
*
* @return The selected color in RGB format with no alpha channel.
*/
@ColorInt
public int getColor() {
return selectedColor;
}
/**
* Sets the listener to be notified when the selected color changes.
*
* @param listener The listener to set.
*/
public void setOnColorChangedListener(OnColorChangedListener listener) {
colorChangedListener = listener;
}
}

View File

@@ -0,0 +1,171 @@
package app.revanced.extension.shared.settings.preference;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import androidx.annotation.NonNull;
import app.revanced.extension.shared.Utils;
/**
* A custom ListPreference that uses a styled custom dialog with a custom checkmark indicator.
*/
@SuppressWarnings({"unused", "deprecation"})
public class CustomDialogListPreference extends ListPreference {
/**
* Custom ArrayAdapter to handle checkmark visibility.
*/
public static class ListPreferenceArrayAdapter extends ArrayAdapter<CharSequence> {
private static class SubViewDataContainer {
ImageView checkIcon;
View placeholder;
TextView itemText;
}
final int layoutResourceId;
final CharSequence[] entryValues;
String selectedValue;
public ListPreferenceArrayAdapter(Context context, int resource, CharSequence[] entries,
CharSequence[] entryValues, String selectedValue) {
super(context, resource, entries);
this.layoutResourceId = resource;
this.entryValues = entryValues;
this.selectedValue = selectedValue;
}
@NonNull
@Override
public View getView(int position, View convertView, @NonNull ViewGroup parent) {
View view = convertView;
SubViewDataContainer holder;
if (view == null) {
LayoutInflater inflater = LayoutInflater.from(getContext());
view = inflater.inflate(layoutResourceId, parent, false);
holder = new SubViewDataContainer();
holder.checkIcon = view.findViewById(Utils.getResourceIdentifier(
"revanced_check_icon", "id"));
holder.placeholder = view.findViewById(Utils.getResourceIdentifier(
"revanced_check_icon_placeholder", "id"));
holder.itemText = view.findViewById(Utils.getResourceIdentifier(
"revanced_item_text", "id"));
view.setTag(holder);
} else {
holder = (SubViewDataContainer) view.getTag();
}
// Set text.
holder.itemText.setText(getItem(position));
holder.itemText.setTextColor(Utils.getAppForegroundColor());
// Show or hide checkmark and placeholder.
String currentValue = entryValues[position].toString();
boolean isSelected = currentValue.equals(selectedValue);
holder.checkIcon.setVisibility(isSelected ? View.VISIBLE : View.GONE);
holder.checkIcon.setColorFilter(Utils.getAppForegroundColor());
holder.placeholder.setVisibility(isSelected ? View.GONE : View.VISIBLE);
return view;
}
public void setSelectedValue(String value) {
this.selectedValue = value;
}
}
public CustomDialogListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public CustomDialogListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomDialogListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomDialogListPreference(Context context) {
super(context);
}
@Override
protected void showDialog(Bundle state) {
Context context = getContext();
// Create ListView.
ListView listView = new ListView(context);
listView.setId(android.R.id.list);
listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
// Create custom adapter for the ListView.
ListPreferenceArrayAdapter adapter = new ListPreferenceArrayAdapter(
context,
Utils.getResourceIdentifier("revanced_custom_list_item_checked", "layout"),
getEntries(),
getEntryValues(),
getValue()
);
listView.setAdapter(adapter);
// Set checked item.
String currentValue = getValue();
if (currentValue != null) {
CharSequence[] entryValues = getEntryValues();
for (int i = 0, length = entryValues.length; i < length; i++) {
if (currentValue.equals(entryValues[i].toString())) {
listView.setItemChecked(i, true);
listView.setSelection(i);
break;
}
}
}
// Create the custom dialog without OK button.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
context,
getTitle() != null ? getTitle().toString() : "",
null,
null,
null, // No OK button text.
null, // No OK button action.
() -> {}, // Cancel button action (just dismiss).
null,
null,
true
);
// Add the ListView to the main layout.
LinearLayout mainLayout = dialogPair.second;
LinearLayout.LayoutParams listViewParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
0,
1.0f
);
mainLayout.addView(listView, mainLayout.getChildCount() - 1, listViewParams);
// Handle item click to select value and dismiss dialog.
listView.setOnItemClickListener((parent, view, position, id) -> {
String selectedValue = getEntryValues()[position].toString();
if (callChangeListener(selectedValue)) {
setValue(selectedValue);
adapter.setSelectedValue(selectedValue);
adapter.notifyDataSetChanged();
}
dialogPair.first.dismiss();
});
// Show the dialog.
dialogPair.first.show();
}
}

View File

@@ -1,19 +1,30 @@
package app.revanced.extension.shared.settings.preference;
import android.app.AlertDialog;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.dipToPixels;
import android.app.Dialog;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;
import android.text.InputType;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Pair;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import app.revanced.extension.shared.settings.Setting;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import static app.revanced.extension.shared.StringRef.str;
import app.revanced.extension.shared.settings.Setting;
@SuppressWarnings({"unused", "deprecation"})
public class ImportExportPreference extends EditTextPreference implements Preference.OnPreferenceClickListener {
@@ -54,7 +65,8 @@ public class ImportExportPreference extends EditTextPreference implements Prefer
@Override
public boolean onPreferenceClick(Preference preference) {
try {
// Must set text before preparing dialog, otherwise text is non selectable if this preference is later reopened.
// Must set text before showing dialog,
// otherwise text is non-selectable if this preference is later reopened.
existingSettings = Setting.exportToJson(getContext());
getEditText().setText(existingSettings);
} catch (Exception ex) {
@@ -64,18 +76,32 @@ public class ImportExportPreference extends EditTextPreference implements Prefer
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
protected void showDialog(Bundle state) {
try {
Utils.setEditTextDialogTheme(builder);
Context context = getContext();
EditText editText = getEditText();
// Show the user the settings in JSON format.
builder.setNeutralButton(str("revanced_settings_import_copy"), (dialog, which) -> {
Utils.setClipboard(getEditText().getText().toString());
}).setPositiveButton(str("revanced_settings_import"), (dialog, which) -> {
importSettings(builder.getContext(), getEditText().getText().toString());
});
// Create a custom dialog with the EditText.
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
context,
str("revanced_pref_import_export_title"), // Title.
null, // No message (EditText replaces it).
editText, // Pass the EditText.
str("revanced_settings_import"), // OK button text.
() -> importSettings(context, editText.getText().toString()), // OK button action.
() -> {}, // Cancel button action (dismiss only).
str("revanced_settings_import_copy"), // Neutral button (Copy) text.
() -> {
// Neutral button (Copy) action. Show the user the settings in JSON format.
Utils.setClipboard(editText.getText());
},
true // Dismiss dialog when onNeutralClick.
);
// Show the dialog.
dialogPair.first.show();
} catch (Exception ex) {
Logger.printException(() -> "onPrepareDialogBuilder failure", ex);
Logger.printException(() -> "showDialog failure", ex);
}
}
@@ -88,7 +114,7 @@ public class ImportExportPreference extends EditTextPreference implements Prefer
final boolean rebootNeeded = Setting.importFromJSON(context, replacementSettings);
if (rebootNeeded) {
AbstractPreferenceFragment.showRestartDialog(getContext());
AbstractPreferenceFragment.showRestartDialog(context);
}
} catch (Exception ex) {
Logger.printException(() -> "importSettings failure", ex);
@@ -96,5 +122,4 @@ public class ImportExportPreference extends EditTextPreference implements Prefer
AbstractPreferenceFragment.settingImportInProgress = false;
}
}
}
}

View File

@@ -0,0 +1,113 @@
package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import java.util.Deque;
import java.util.Objects;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.atomic.AtomicInteger;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings;
/**
* Manages a buffer for storing debug logs from {@link Logger}.
* Stores just under 1MB of the most recent log data.
*
* All methods are thread-safe.
*/
public final class LogBufferManager {
/** Maximum byte size of all buffer entries. Must be less than Android's 1 MB Binder transaction limit. */
private static final int BUFFER_MAX_BYTES = 900_000;
/** Limit number of log lines. */
private static final int BUFFER_MAX_SIZE = 10_000;
private static final Deque<String> logBuffer = new ConcurrentLinkedDeque<>();
private static final AtomicInteger logBufferByteSize = new AtomicInteger();
/**
* Appends a log message to the internal buffer if debugging is enabled.
* The buffer is limited to approximately {@link #BUFFER_MAX_BYTES} or {@link #BUFFER_MAX_SIZE}
* to prevent excessive memory usage.
*
* @param message The log message to append.
*/
public static void appendToLogBuffer(String message) {
Objects.requireNonNull(message);
// It's very important that no Settings are used in this method,
// as this code is used when a context is not set and thus referencing
// a setting will crash the app.
logBuffer.addLast(message);
int newSize = logBufferByteSize.addAndGet(message.length());
// Remove oldest entries if over the log size limits.
while (newSize > BUFFER_MAX_BYTES || logBuffer.size() > BUFFER_MAX_SIZE) {
String removed = logBuffer.pollFirst();
if (removed == null) {
// Thread race of two different calls to this method, and the other thread won.
return;
}
newSize = logBufferByteSize.addAndGet(-removed.length());
}
}
/**
* Exports all logs from the internal buffer to the clipboard.
* Displays a toast with the result.
*/
public static void exportToClipboard() {
try {
if (!BaseSettings.DEBUG.get()) {
Utils.showToastShort(str("revanced_debug_logs_disabled"));
return;
}
if (logBuffer.isEmpty()) {
Utils.showToastShort(str("revanced_debug_logs_none_found"));
clearLogBufferData(); // Clear toast log entry that was just created.
return;
}
// Most (but not all) Android 13+ devices always show a "copied to clipboard" toast
// and there is no way to programmatically detect if a toast will show or not.
// Show a toast even if using Android 13+, but show ReVanced toast first (before copying to clipboard).
Utils.showToastShort(str("revanced_debug_logs_copied_to_clipboard"));
Utils.setClipboard(String.join("\n", logBuffer));
} catch (Exception ex) {
// Handle security exception if clipboard access is denied.
String errorMessage = String.format(str("revanced_debug_logs_failed_to_export"), ex.getMessage());
Utils.showToastLong(errorMessage);
Logger.printDebug(() -> errorMessage, ex);
}
}
private static void clearLogBufferData() {
// Cannot simply clear the log buffer because there is no
// write lock for both the deque and the atomic int.
// Instead pop off log entries and decrement the size one by one.
while (!logBuffer.isEmpty()) {
String removed = logBuffer.pollFirst();
if (removed != null) {
logBufferByteSize.addAndGet(-removed.length());
}
}
}
/**
* Clears the internal log buffer and displays a toast with the result.
*/
public static void clearLogBuffer() {
if (!BaseSettings.DEBUG.get()) {
Utils.showToastShort(str("revanced_debug_logs_disabled"));
return;
}
// Show toast before clearing, otherwise toast log will still remain.
Utils.showToastShort(str("revanced_debug_logs_clear_toast"));
clearLogBufferData();
}
}

View File

@@ -21,6 +21,10 @@ public class NoTitlePreferenceCategory extends PreferenceCategory {
super(context, attrs, defStyleAttr);
}
public NoTitlePreferenceCategory(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public NoTitlePreferenceCategory(Context context) {
super(context);
}

View File

@@ -1,6 +1,7 @@
package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.dipToPixels;
import static app.revanced.extension.shared.requests.Route.Method.GET;
import android.annotation.SuppressLint;
@@ -8,17 +9,19 @@ import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RoundRectShape;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.Preference;
import android.util.AttributeSet;
import android.view.View;
import android.view.Window;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -49,28 +52,6 @@ public class ReVancedAboutPreference extends Preference {
return text.replace("-", "&#8209;"); // #8209 = non breaking hyphen.
}
private static String getColorHexString(int color) {
return String.format("#%06X", (0x00FFFFFF & color));
}
protected boolean isDarkModeEnabled() {
return Utils.isDarkModeEnabled(getContext());
}
/**
* Subclasses can override this and provide a themed color.
*/
protected int getLightColor() {
return Color.WHITE;
}
/**
* Subclasses can override this and provide a themed color.
*/
protected int getDarkColor() {
return Color.BLACK;
}
/**
* Apps that do not support bundling resources must override this.
*
@@ -87,9 +68,8 @@ public class ReVancedAboutPreference extends Preference {
builder.append("<html>");
builder.append("<body style=\"text-align: center; padding: 10px;\">");
final boolean isDarkMode = isDarkModeEnabled();
String backgroundColorHex = getColorHexString(isDarkMode ? getDarkColor() : getLightColor());
String foregroundColorHex = getColorHexString(isDarkMode ? getLightColor() : getDarkColor());
String foregroundColorHex = Utils.getColorHexString(Utils.getAppForegroundColor());
String backgroundColorHex = Utils.getColorHexString(Utils.getDialogBackgroundColor());
// Apply light/dark mode colors.
builder.append(String.format(
"<style> body { background-color: %s; color: %s; } a { color: %s; } </style>",
@@ -221,14 +201,38 @@ class WebViewDialog extends Dialog {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
requestWindowFeature(Window.FEATURE_NO_TITLE); // Remove default title bar.
// Create main layout.
LinearLayout mainLayout = new LinearLayout(getContext());
mainLayout.setOrientation(LinearLayout.VERTICAL);
final int padding = dipToPixels(10);
mainLayout.setPadding(padding, padding, padding, padding);
// Set rounded rectangle background.
ShapeDrawable mainBackground = new ShapeDrawable(new RoundRectShape(
Utils.createCornerRadii(28), null, null));
mainBackground.getPaint().setColor(Utils.getDialogBackgroundColor());
mainLayout.setBackground(mainBackground);
// Create WebView.
WebView webView = new WebView(getContext());
webView.setVerticalScrollBarEnabled(false); // Disable the vertical scrollbar.
webView.setOverScrollMode(View.OVER_SCROLL_NEVER);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new OpenLinksExternallyWebClient());
webView.loadDataWithBaseURL(null, htmlContent, "text/html", "utf-8", null);
setContentView(webView);
// Add WebView to layout.
mainLayout.addView(webView);
setContentView(mainLayout);
// Set dialog window attributes
Window window = getWindow();
if (window != null) {
Utils.setDialogWindowParameters(window);
}
}
private class OpenLinksExternallyWebClient extends WebViewClient {
@@ -316,7 +320,7 @@ class AboutLinksRoutes {
// Do not show an exception toast if the server is down
final int responseCode = connection.getResponseCode();
if (responseCode != 200) {
Logger.printDebug(() -> "Failed to get social links. Response code: " + responseCode);
Logger.printDebug(() -> "Failed to get social links. Response code: " + responseCode);
return NO_CONNECTION_STATIC_LINKS;
}

View File

@@ -2,13 +2,14 @@ package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.widget.Button;
import android.util.Pair;
import android.widget.EditText;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
@@ -44,41 +45,61 @@ public class ResettableEditTextPreference extends EditTextPreference {
this.setting = setting;
}
@Override
protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
super.onPrepareDialogBuilder(builder);
Utils.setEditTextDialogTheme(builder);
if (setting == null) {
String key = getKey();
if (key != null) {
setting = Setting.getSettingFromPath(key);
}
}
if (setting != null) {
builder.setNeutralButton(str("revanced_settings_reset"), null);
}
}
@Override
protected void showDialog(Bundle state) {
super.showDialog(state);
try {
Context context = getContext();
EditText editText = getEditText();
// Override the button click listener to prevent dismissing the dialog.
Button button = ((AlertDialog) getDialog()).getButton(AlertDialog.BUTTON_NEUTRAL);
if (button == null) {
return;
}
button.setOnClickListener(v -> {
try {
String defaultStringValue = Objects.requireNonNull(setting).defaultValue.toString();
EditText editText = getEditText();
editText.setText(defaultStringValue);
editText.setSelection(defaultStringValue.length()); // move cursor to end of text
} catch (Exception ex) {
Logger.printException(() -> "reset failure", ex);
// Resolve setting if not already set.
if (setting == null) {
String key = getKey();
if (key != null) {
setting = Setting.getSettingFromPath(key);
}
}
});
// Set initial EditText value to the current persisted value or empty string.
String initialValue = getText() != null ? getText() : "";
editText.setText(initialValue);
editText.setSelection(initialValue.length()); // Move cursor to end.
// Create custom dialog.
String neutralButtonText = (setting != null) ? str("revanced_settings_reset") : null;
Pair<Dialog, LinearLayout> dialogPair = Utils.createCustomDialog(
context,
getTitle() != null ? getTitle().toString() : "", // Title.
null, // Message is replaced by EditText.
editText, // Pass the EditText.
null, // OK button text.
() -> {
// OK button action. Persist the EditText value when OK is clicked.
String newValue = editText.getText().toString();
if (callChangeListener(newValue)) {
setText(newValue);
}
},
() -> {}, // Cancel button action (dismiss only).
neutralButtonText, // Neutral button text (Reset).
() -> {
// Neutral button action.
if (setting != null) {
try {
String defaultStringValue = Objects.requireNonNull(setting).defaultValue.toString();
editText.setText(defaultStringValue);
editText.setSelection(defaultStringValue.length()); // Move cursor to end of text.
} catch (Exception ex) {
Logger.printException(() -> "reset failure", ex);
}
}
},
false // Do not dismiss dialog when onNeutralClick.
);
// Show the dialog.
dialogPair.first.show();
} catch (Exception ex) {
Logger.printException(() -> "showDialog failure", ex);
}
}
}

View File

@@ -0,0 +1,124 @@
package app.revanced.extension.shared.settings.preference;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Pair;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import app.revanced.extension.shared.Utils;
/**
* PreferenceList that sorts itself.
* By default the first entry is preserved in its original position,
* and all other entries are sorted alphabetically.
*
* Ideally the 'keep first entries to preserve' is an xml parameter,
* but currently that's not so simple since Extensions code cannot use
* generated code from the Patches repo (which is required for custom xml parameters).
*
* If any class wants to use a different getFirstEntriesToPreserve value,
* it needs to subclass this preference and override {@link #getFirstEntriesToPreserve}.
*/
@SuppressWarnings({"unused", "deprecation"})
public class SortedListPreference extends CustomDialogListPreference {
/**
* Sorts the current list entries.
*
* @param firstEntriesToPreserve The number of entries to preserve in their original position,
* or a negative value to not sort and leave entries
* as they current are.
*/
public void sortEntryAndValues(int firstEntriesToPreserve) {
CharSequence[] entries = getEntries();
CharSequence[] entryValues = getEntryValues();
if (entries == null || entryValues == null) {
return;
}
final int entrySize = entries.length;
if (entrySize != entryValues.length) {
// Xml array declaration has a missing/extra entry.
throw new IllegalStateException();
}
if (firstEntriesToPreserve < 0) {
return; // Nothing to do.
}
List<Pair<CharSequence, CharSequence>> firstEntries = new ArrayList<>(firstEntriesToPreserve);
// Android does not have a triple class like Kotlin, So instead use a nested pair.
// Cannot easily use a SortedMap, because if two entries incorrectly have
// identical names then the duplicates entries are not preserved.
List<Pair<String, Pair<CharSequence, CharSequence>>> lastEntries = new ArrayList<>();
for (int i = 0; i < entrySize; i++) {
Pair<CharSequence, CharSequence> pair = new Pair<>(entries[i], entryValues[i]);
if (i < firstEntriesToPreserve) {
firstEntries.add(pair);
} else {
lastEntries.add(new Pair<>(Utils.removePunctuationToLowercase(pair.first), pair));
}
}
//noinspection ComparatorCombinators
Collections.sort(lastEntries, (pair1, pair2)
-> pair1.first.compareTo(pair2.first));
CharSequence[] sortedEntries = new CharSequence[entrySize];
CharSequence[] sortedEntryValues = new CharSequence[entrySize];
int i = 0;
for (Pair<CharSequence, CharSequence> pair : firstEntries) {
sortedEntries[i] = pair.first;
sortedEntryValues[i] = pair.second;
i++;
}
for (Pair<String, Pair<CharSequence, CharSequence>> outer : lastEntries) {
Pair<CharSequence, CharSequence> inner = outer.second;
sortedEntries[i] = inner.first;
sortedEntryValues[i] = inner.second;
i++;
}
super.setEntries(sortedEntries);
super.setEntryValues(sortedEntryValues);
}
public SortedListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
sortEntryAndValues(getFirstEntriesToPreserve());
}
public SortedListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
sortEntryAndValues(getFirstEntriesToPreserve());
}
public SortedListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
sortEntryAndValues(getFirstEntriesToPreserve());
}
public SortedListPreference(Context context) {
super(context);
sortEntryAndValues(getFirstEntriesToPreserve());
}
/**
* @return The number of first entries to leave exactly where they are, and do not sort them.
* A negative value indicates do not sort any entries.
*/
protected int getFirstEntriesToPreserve() {
return 1;
}
}

View File

@@ -71,9 +71,7 @@ final class PlayerRoutes {
return innerTubeBody.toString();
}
/**
* @noinspection SameParameterValue
*/
@SuppressWarnings("SameParameterValue")
static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route, ClientType clientType) throws IOException {
var connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route);

View File

@@ -204,7 +204,7 @@ public class StreamingDataRequest {
// but empty response body does.
if (connection.getContentLength() == 0) {
if (BaseSettings.DEBUG.get() && BaseSettings.DEBUG_TOAST_ON_ERROR.get()) {
Utils.showToastShort("Ignoring empty spoof stream client: " + clientType);
Utils.showToastShort("Debug: Ignoring empty spoof stream client " + clientType);
}
} else {
try (InputStream inputStream = new BufferedInputStream(connection.getInputStream());

View File

@@ -1,16 +1,39 @@
plugins {
alias(libs.plugins.protobuf)
}
dependencies {
compileOnly(project(":extensions:shared:library"))
compileOnly(project(":extensions:spotify:stub"))
compileOnly(libs.annotation)
implementation(libs.nanohttpd)
implementation(libs.protobuf.javalite)
}
android {
defaultConfig {
minSdk = 24
minSdk = 21
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}
protobuf {
protoc {
artifact = libs.protobuf.protoc.get().toString()
}
generateProtoTasks {
all().forEach { task ->
task.builtins {
create("java") {
option("lite")
}
}
}
}
}

View File

@@ -0,0 +1,86 @@
package app.revanced.extension.spotify.layout.hide.createbutton;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.spotify.shared.ComponentFilters.ComponentFilter;
import app.revanced.extension.spotify.shared.ComponentFilters.ResourceIdComponentFilter;
import app.revanced.extension.spotify.shared.ComponentFilters.StringComponentFilter;
import java.util.List;
@SuppressWarnings("unused")
public final class HideCreateButtonPatch {
/**
* A list of component filters that match whether a navigation bar item is the Create button.
* The main approach used is matching the resource id for the Create button title.
*/
private static final List<ComponentFilter> CREATE_BUTTON_COMPONENT_FILTERS = List.of(
new ResourceIdComponentFilter("navigationbar_musicappitems_create_title", "string"),
// Temporary fallback and fix for APKs merged with AntiSplit-M not having resources properly encoded,
// and thus getting the resource identifier for the Create button title always return 0.
// FIXME: Remove this once the above issue is no longer relevant.
new StringComponentFilter("spotify:create-menu")
);
/**
* A component filter for the old id of the resource which contained the Create button title.
* Used in older versions of the app.
*/
private static final ResourceIdComponentFilter OLD_CREATE_BUTTON_COMPONENT_FILTER =
new ResourceIdComponentFilter("bottom_navigation_bar_create_tab_title", "string");
/**
* Injection point. This method is called on every navigation bar item to check whether it is the Create button.
* If the navigation bar item is the Create button, it returns null to erase it.
* The method fingerprint used to patch ensures we can safely return null here.
*/
public static Object returnNullIfIsCreateButton(Object navigationBarItem) {
if (navigationBarItem == null) {
return null;
}
try {
String stringifiedNavigationBarItem = navigationBarItem.toString();
for (ComponentFilter componentFilter : CREATE_BUTTON_COMPONENT_FILTERS) {
if (componentFilter.filterUnavailable()) {
Logger.printInfo(() -> "returnNullIfIsCreateButton: Filter " +
componentFilter.getFilterRepresentation() + " not available, skipping");
continue;
}
if (stringifiedNavigationBarItem.contains(componentFilter.getFilterValue())) {
Logger.printInfo(() -> "Hiding Create button because the navigation bar item " +
navigationBarItem + " matched the filter " + componentFilter.getFilterRepresentation());
return null;
}
}
} catch (Throwable ex) {
// Catch Throwable as calling toString can cause crashes with wrongfully generated code that throws
// NoSuchMethod errors.
Logger.printException(() -> "returnNullIfIsCreateButton failure", ex);
}
return navigationBarItem;
}
/**
* Injection point. Called in older versions of the app. Returns whether the old navigation bar item is the old
* Create button.
*/
public static boolean isOldCreateButton(int oldNavigationBarItemTitleResId) {
if (OLD_CREATE_BUTTON_COMPONENT_FILTER.filterUnavailable()) {
Logger.printInfo(() -> "Skipping hiding old Create button because the resource id for " +
OLD_CREATE_BUTTON_COMPONENT_FILTER.resourceName + " is not available");
return false;
}
if (oldNavigationBarItemTitleResId == OLD_CREATE_BUTTON_COMPONENT_FILTER.getResourceId()) {
Logger.printInfo(() -> "Hiding old Create button because the navigation bar item title resource id" +
" matched " + OLD_CREATE_BUTTON_COMPONENT_FILTER.getFilterRepresentation());
return true;
}
return false;
}
}

View File

@@ -8,15 +8,54 @@ import app.revanced.extension.shared.Utils;
@SuppressWarnings("unused")
public final class CustomThemePatch {
private static final int BACKGROUND_COLOR = getColorFromString("@color/gray_7");
private static final int BACKGROUND_COLOR_SECONDARY = getColorFromString("@color/gray_15");
private static final int ACCENT_COLOR = getColorFromString("@color/spotify_green_157");
private static final int ACCENT_PRESSED_COLOR =
getColorFromString("@color/dark_brightaccent_background_press");
/**
* Injection point.
* Returns an int representation of the color resource or hex code.
*/
public static long getThemeColor(String colorString) {
private static int getColorFromString(String colorString) {
try {
return Utils.getColorFromString(colorString);
} catch (Exception ex) {
Logger.printException(() -> "Invalid custom color: " + colorString, ex);
Logger.printException(() -> "Invalid color string: " + colorString, ex);
return Color.BLACK;
}
}
/**
* Injection point. Returns an int representation of the replaced color from the original color.
*/
public static int replaceColor(int originalColor) {
switch (originalColor) {
// Playlist background color.
case 0xFF121212:
return BACKGROUND_COLOR;
// Share menu background color.
case 0xFF1F1F1F:
// Home category pills background color.
case 0xFF333333:
// Settings header background color.
case 0xFF282828:
// Spotify Connect device list background color.
case 0xFF2A2A2A:
return BACKGROUND_COLOR_SECONDARY;
// Some Lottie animations have a color that's slightly off due to rounding errors.
case 0xFF1ED760: case 0xFF1ED75F:
// Intermediate color used in some animations, same rounding issue.
case 0xFF1DB954: case 0xFF1CB854:
return ACCENT_COLOR;
case 0xFF1ABC54:
return ACCENT_PRESSED_COLOR;
default:
return originalColor;
}
}
}

View File

@@ -0,0 +1,115 @@
package app.revanced.extension.spotify.misc.fix;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.spotify.misc.fix.clienttoken.data.v0.ClienttokenHttp.*;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import static app.revanced.extension.spotify.misc.fix.Constants.*;
class ClientTokenService {
private static final String IOS_CLIENT_ID = "58bd3c95768941ea9eb4350aaa033eb3";
private static final String IOS_USER_AGENT;
static {
String clientVersion = getClientVersion();
int commitHashIndex = clientVersion.lastIndexOf(".");
String version = clientVersion.substring(
clientVersion.indexOf("-") + 1,
clientVersion.lastIndexOf(".", commitHashIndex - 1)
);
IOS_USER_AGENT = "Spotify/" + version + " iOS/" + getSystemVersion() + " (" + getHardwareMachine() + ")";
}
private static final ConnectivitySdkData.Builder IOS_CONNECTIVITY_SDK_DATA =
ConnectivitySdkData.newBuilder()
.setPlatformSpecificData(PlatformSpecificData.newBuilder()
.setIos(NativeIOSData.newBuilder()
.setHwMachine(getHardwareMachine())
.setSystemVersion(getSystemVersion())
)
);
private static final ClientDataRequest.Builder IOS_CLIENT_DATA_REQUEST =
ClientDataRequest.newBuilder()
.setClientVersion(getClientVersion())
.setClientId(IOS_CLIENT_ID);
private static final ClientTokenRequest.Builder IOS_CLIENT_TOKEN_REQUEST =
ClientTokenRequest.newBuilder()
.setRequestType(ClientTokenRequestType.REQUEST_CLIENT_DATA_REQUEST);
@NonNull
static ClientTokenRequest newIOSClientTokenRequest(String deviceId) {
Logger.printInfo(() -> "Creating new iOS client token request with device ID: " + deviceId);
return IOS_CLIENT_TOKEN_REQUEST
.setClientData(IOS_CLIENT_DATA_REQUEST
.setConnectivitySdkData(IOS_CONNECTIVITY_SDK_DATA
.setDeviceId(deviceId)
)
)
.build();
}
@Nullable
static ClientTokenResponse getClientTokenResponse(@NonNull ClientTokenRequest request) {
if (request.getRequestType() == ClientTokenRequestType.REQUEST_CLIENT_DATA_REQUEST) {
Logger.printInfo(() -> "Requesting iOS client token");
String deviceId = request.getClientData().getConnectivitySdkData().getDeviceId();
request = newIOSClientTokenRequest(deviceId);
}
ClientTokenResponse response;
try {
response = requestClientToken(request);
} catch (IOException ex) {
Logger.printException(() -> "Failed to handle request", ex);
return null;
}
return response;
}
@NonNull
private static ClientTokenResponse requestClientToken(@NonNull ClientTokenRequest request) throws IOException {
HttpURLConnection urlConnection = (HttpURLConnection) new URL(CLIENT_TOKEN_API_URL).openConnection();
urlConnection.setRequestMethod("POST");
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Content-Type", "application/x-protobuf");
urlConnection.setRequestProperty("Accept", "application/x-protobuf");
urlConnection.setRequestProperty("User-Agent", IOS_USER_AGENT);
byte[] requestArray = request.toByteArray();
urlConnection.setFixedLengthStreamingMode(requestArray.length);
urlConnection.getOutputStream().write(requestArray);
try (InputStream inputStream = urlConnection.getInputStream()) {
return ClientTokenResponse.parseFrom(inputStream);
}
}
@Nullable
static ClientTokenResponse serveClientTokenRequest(@NonNull InputStream inputStream) {
ClientTokenRequest request;
try {
request = ClientTokenRequest.parseFrom(inputStream);
} catch (IOException ex) {
Logger.printException(() -> "Failed to parse request from input stream", ex);
return null;
}
Logger.printInfo(() -> "Request of type: " + request.getRequestType());
ClientTokenResponse response = getClientTokenResponse(request);
if (response != null) Logger.printInfo(() -> "Response of type: " + response.getResponseType());
return response;
}
}

View File

@@ -0,0 +1,26 @@
package app.revanced.extension.spotify.misc.fix;
import androidx.annotation.NonNull;
class Constants {
static final String CLIENT_TOKEN_API_PATH = "/v1/clienttoken";
static final String CLIENT_TOKEN_API_URL = "https://clienttoken.spotify.com" + CLIENT_TOKEN_API_PATH;
// Modified by a patch. Do not touch.
@NonNull
static String getClientVersion() {
return "";
}
// Modified by a patch. Do not touch.
@NonNull
static String getSystemVersion() {
return "";
}
// Modified by a patch. Do not touch.
@NonNull
static String getHardwareMachine() {
return "";
}
}

View File

@@ -0,0 +1,94 @@
package app.revanced.extension.spotify.misc.fix;
import androidx.annotation.NonNull;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.spotify.misc.fix.clienttoken.data.v0.ClienttokenHttp.ClientTokenResponse;
import com.google.protobuf.MessageLite;
import fi.iki.elonen.NanoHTTPD;
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import static app.revanced.extension.spotify.misc.fix.ClientTokenService.serveClientTokenRequest;
import static app.revanced.extension.spotify.misc.fix.Constants.CLIENT_TOKEN_API_PATH;
import static fi.iki.elonen.NanoHTTPD.Response.Status.INTERNAL_ERROR;
class RequestListener extends NanoHTTPD {
RequestListener(int port) {
super(port);
try {
start();
} catch (IOException ex) {
Logger.printException(() -> "Failed to start request listener on port " + port, ex);
throw new RuntimeException(ex);
}
}
@NonNull
@Override
public Response serve(@NonNull IHTTPSession session) {
String uri = session.getUri();
if (!uri.equals(CLIENT_TOKEN_API_PATH)) return INTERNAL_ERROR_RESPONSE;
Logger.printInfo(() -> "Serving request for URI: " + uri);
ClientTokenResponse response = serveClientTokenRequest(getInputStream(session));
if (response != null) return newResponse(Response.Status.OK, response);
Logger.printException(() -> "Failed to serve client token request");
return INTERNAL_ERROR_RESPONSE;
}
@NonNull
private static InputStream newLimitedInputStream(InputStream inputStream, long contentLength) {
return new FilterInputStream(inputStream) {
private long remaining = contentLength;
@Override
public int read() throws IOException {
if (remaining <= 0) return -1;
int result = super.read();
if (result != -1) remaining--;
return result;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (remaining <= 0) return -1;
len = (int) Math.min(len, remaining);
int result = super.read(b, off, len);
if (result != -1) remaining -= result;
return result;
}
};
}
@NonNull
private static InputStream getInputStream(@NonNull IHTTPSession session) {
long requestContentLength = Long.parseLong(Objects.requireNonNull(session.getHeaders().get("content-length")));
return newLimitedInputStream(session.getInputStream(), requestContentLength);
}
private static final Response INTERNAL_ERROR_RESPONSE = newResponse(INTERNAL_ERROR);
@SuppressWarnings("SameParameterValue")
@NonNull
private static Response newResponse(Response.Status status) {
return newResponse(status, null);
}
@NonNull
private static Response newResponse(Response.IStatus status, MessageLite messageLite) {
if (messageLite == null) {
return newFixedLengthResponse(status, "application/x-protobuf", null);
}
byte[] messageBytes = messageLite.toByteArray();
InputStream stream = new ByteArrayInputStream(messageBytes);
return newFixedLengthResponse(status, "application/x-protobuf", stream, messageBytes.length);
}
}

View File

@@ -0,0 +1,25 @@
package app.revanced.extension.spotify.misc.fix;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public class SpoofClientPatch {
private static RequestListener listener;
/**
* Injection point. Launch requests listener server.
*/
public synchronized static void launchListener(int port) {
if (listener != null) {
Logger.printInfo(() -> "Listener already running on port " + port);
return;
}
try {
Logger.printInfo(() -> "Launching listener on port " + port);
listener = new RequestListener(port);
} catch (Exception ex) {
Logger.printException(() -> "launchListener failure", ex);
}
}
}

View File

@@ -0,0 +1,44 @@
package app.revanced.extension.spotify.misc.privacy;
import android.net.Uri;
import java.util.List;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused")
public final class SanitizeSharingLinksPatch {
/**
* Parameters that are considered undesirable and should be stripped away.
*/
private static final List<String> SHARE_PARAMETERS_TO_REMOVE = List.of(
"si", // Share tracking parameter.
"utm_source" // Share source, such as "copy-link".
);
/**
* Injection point.
*/
public static String sanitizeUrl(String url) {
try {
Uri uri = Uri.parse(url);
Uri.Builder builder = uri.buildUpon().clearQuery();
for (String paramName : uri.getQueryParameterNames()) {
if (!SHARE_PARAMETERS_TO_REMOVE.contains(paramName)) {
for (String value : uri.getQueryParameters(paramName)) {
builder.appendQueryParameter(paramName, value);
}
}
}
String sanitizedUrl = builder.build().toString();
Logger.printInfo(() -> "Sanitized url " + url + " to " + sanitizedUrl);
return sanitizedUrl;
} catch (Exception ex) {
Logger.printException(() -> "sanitizeUrl failure with " + url, ex);
return url;
}
}
}

View File

@@ -0,0 +1,85 @@
package app.revanced.extension.spotify.shared;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
public final class ComponentFilters {
public interface ComponentFilter {
@NonNull
String getFilterValue();
String getFilterRepresentation();
default boolean filterUnavailable() {
return false;
}
}
public static final class ResourceIdComponentFilter implements ComponentFilter {
public final String resourceName;
public final String resourceType;
// Android resources are always positive, so -1 is a valid sentinel value to indicate it has not been loaded.
// 0 is returned when a resource has not been found.
private int resourceId = -1;
@Nullable
private String stringfiedResourceId;
public ResourceIdComponentFilter(String resourceName, String resourceType) {
this.resourceName = resourceName;
this.resourceType = resourceType;
}
public int getResourceId() {
if (resourceId == -1) {
resourceId = Utils.getResourceIdentifier(resourceName, resourceType);
}
return resourceId;
}
@NonNull
@Override
public String getFilterValue() {
if (stringfiedResourceId == null) {
stringfiedResourceId = Integer.toString(getResourceId());
}
return stringfiedResourceId;
}
@Override
public String getFilterRepresentation() {
boolean resourceFound = getResourceId() != 0;
return (resourceFound ? getFilterValue() + " (" : "") + resourceName + (resourceFound ? ")" : "");
}
@Override
public boolean filterUnavailable() {
boolean resourceNotFound = getResourceId() == 0;
if (resourceNotFound) {
Logger.printInfo(() -> "Resource id for " + resourceName + " was not found");
}
return resourceNotFound;
}
}
public static final class StringComponentFilter implements ComponentFilter {
public final String string;
public StringComponentFilter(String string) {
this.string = string;
}
@NonNull
@Override
public String getFilterValue() {
return string;
}
@Override
public String getFilterRepresentation() {
return string;
}
}
}

View File

@@ -0,0 +1,73 @@
syntax = "proto3";
package spotify.clienttoken.data.v0;
option optimize_for = LITE_RUNTIME;
option java_package = "app.revanced.extension.spotify.misc.fix.clienttoken.data.v0";
message ClientTokenRequest {
ClientTokenRequestType request_type = 1;
oneof request {
ClientDataRequest client_data = 2;
}
}
enum ClientTokenRequestType {
REQUEST_UNKNOWN = 0;
REQUEST_CLIENT_DATA_REQUEST = 1;
REQUEST_CHALLENGE_ANSWERS_REQUEST = 2;
}
message ClientDataRequest {
string client_version = 1;
string client_id = 2;
oneof data {
ConnectivitySdkData connectivity_sdk_data = 3;
}
}
message ConnectivitySdkData {
PlatformSpecificData platform_specific_data = 1;
string device_id = 2;
}
message PlatformSpecificData {
oneof data {
NativeIOSData ios = 2;
}
}
message NativeIOSData {
int32 user_interface_idiom = 1;
bool target_iphone_simulator = 2;
string hw_machine = 3;
string system_version = 4;
string simulator_model_identifier = 5;
}
message ClientTokenResponse {
ClientTokenResponseType response_type = 1;
oneof response {
GrantedTokenResponse granted_token = 2;
}
}
enum ClientTokenResponseType {
RESPONSE_UNKNOWN = 0;
RESPONSE_GRANTED_TOKEN_RESPONSE = 1;
RESPONSE_CHALLENGES_RESPONSE = 2;
}
message GrantedTokenResponse {
string token = 1;
int32 expires_after_seconds = 2;
int32 refresh_after_seconds = 3;
repeated TokenDomain domains = 4;
}
message TokenDomain {
string domain = 1;
}

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {
@@ -7,11 +7,11 @@ android {
compileSdk = 34
defaultConfig {
minSdk = 26
minSdk = 21
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
}

View File

@@ -0,0 +1,5 @@
package app.revanced;
public interface ContextMenuItemPlaceholder {
Object getViewModel();
}

View File

@@ -0,0 +1,6 @@
package com.spotify.browsita.v1.resolved;
public final class Section {
public static final int BRAND_ADS_FIELD_NUMBER = 6;
public int sectionTypeCase_;
}

View File

@@ -1,8 +0,0 @@
package com.spotify.useraccount.v1;
/**
* Used for target 8.6.98.900. Class is still present in newer app targets.
*/
public class AccountAttribute {
public Object value_;
}

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

View File

@@ -2,7 +2,6 @@ package app.revanced.extension.tiktok;
import static app.revanced.extension.shared.Utils.isDarkModeEnabled;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.TextView;
@@ -43,8 +42,8 @@ public class Utils {
private static final @ColorInt int TEXT_LIGHT_MODE_SUMMARY
= Color.argb(255, 80, 80, 80);
public static void setTitleAndSummaryColor(Context context, View view) {
final boolean darkModeEnabled = isDarkModeEnabled(context);
public static void setTitleAndSummaryColor(View view) {
final boolean darkModeEnabled = isDarkModeEnabled();
TextView title = view.findViewById(android.R.id.title);
title.setTextColor(darkModeEnabled

View File

@@ -2,6 +2,7 @@ package app.revanced.extension.tiktok.feedfilter;
import com.ss.android.ugc.aweme.feed.model.Aweme;
import com.ss.android.ugc.aweme.feed.model.FeedItemList;
import com.ss.android.ugc.aweme.follow.presenter.FollowFeedList;
import java.util.Iterator;
import java.util.List;
@@ -13,22 +14,41 @@ public final class FeedItemsFilter {
new StoryFilter(),
new ImageVideoFilter(),
new ViewCountFilter(),
new LikeCountFilter()
new LikeCountFilter(),
new ShopFilter()
);
public static void filter(FeedItemList feedItemList) {
Iterator<Aweme> feedItemListIterator = feedItemList.items.iterator();
while (feedItemListIterator.hasNext()) {
Aweme item = feedItemListIterator.next();
if (item == null) continue;
filterFeedList(feedItemList.items, item -> item);
}
for (IFilter filter : FILTERS) {
boolean enabled = filter.getEnabled();
if (enabled && filter.getFiltered(item)) {
feedItemListIterator.remove();
break;
}
public static void filter(FollowFeedList followFeedList) {
filterFeedList(followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null);
}
private static <T> void filterFeedList(List<T> list, AwemeExtractor<T> extractor) {
// Could be simplified with removeIf() but requires Android 7.0+ while TikTok supports 4.0+.
Iterator<T> iterator = list.iterator();
while (iterator.hasNext()) {
T container = iterator.next();
Aweme item = extractor.extract(container);
if (item != null && shouldFilter(item)) {
iterator.remove();
}
}
}
}
private static boolean shouldFilter(Aweme item) {
for (IFilter filter : FILTERS) {
if (filter.getEnabled() && filter.getFiltered(item)) {
return true;
}
}
return false;
}
@FunctionalInterface
interface AwemeExtractor<T> {
Aweme extract(T source);
}
}

View File

@@ -0,0 +1,17 @@
package app.revanced.extension.tiktok.feedfilter;
import app.revanced.extension.tiktok.settings.Settings;
import com.ss.android.ugc.aweme.feed.model.Aweme;
public class ShopFilter implements IFilter {
private static final String SHOP_INFO = "placeholder_product_id";
@Override
public boolean getEnabled() {
return Settings.HIDE_SHOP.get();
}
@Override
public boolean getFiltered(Aweme item) {
return item.getShareUrl().contains(SHOP_INFO);
}
}

View File

@@ -11,6 +11,7 @@ import app.revanced.extension.shared.settings.StringSetting;
public class Settings extends BaseSettings {
public static final BooleanSetting REMOVE_ADS = new BooleanSetting("remove_ads", TRUE, true);
public static final BooleanSetting HIDE_LIVE = new BooleanSetting("hide_live", FALSE, true);
public static final BooleanSetting HIDE_SHOP = new BooleanSetting("hide_shop", FALSE, true);
public static final BooleanSetting HIDE_STORY = new BooleanSetting("hide_story", FALSE, true);
public static final BooleanSetting HIDE_IMAGE = new BooleanSetting("hide_image", FALSE, true);
public static final StringSetting MIN_MAX_VIEWS = new StringSetting("min_max_views", "0-" + Long.MAX_VALUE, true);

View File

@@ -101,7 +101,7 @@ public class DownloadPathPreference extends DialogPreference {
protected void onBindView(View view) {
super.onBindView(view);
Utils.setTitleAndSummaryColor(getContext(), view);
Utils.setTitleAndSummaryColor(view);
}
@Override

View File

@@ -22,6 +22,6 @@ public class InputTextPreference extends EditTextPreference {
protected void onBindView(View view) {
super.onBindView(view);
Utils.setTitleAndSummaryColor(getContext(), view);
Utils.setTitleAndSummaryColor(view);
}
}

View File

@@ -127,7 +127,7 @@ public class RangeValuePreference extends DialogPreference {
protected void onBindView(View view) {
super.onBindView(view);
Utils.setTitleAndSummaryColor(getContext(), view);
Utils.setTitleAndSummaryColor(view);
}
@Override

View File

@@ -48,6 +48,6 @@ public class ReVancedTikTokAboutPreference extends ReVancedAboutPreference {
protected void onBindView(View view) {
super.onBindView(view);
Utils.setTitleAndSummaryColor(getContext(), view);
Utils.setTitleAndSummaryColor(view);
}
}

View File

@@ -22,6 +22,6 @@ public class TogglePreference extends SwitchPreference {
protected void onBindView(View view) {
super.onBindView(view);
Utils.setTitleAndSummaryColor(getContext(), view);
Utils.setTitleAndSummaryColor(view);
}
}

View File

@@ -26,6 +26,11 @@ public class FeedFilterPreferenceCategory extends ConditionalPreferenceCategory
"Remove feed ads", "Remove ads from feed.",
Settings.REMOVE_ADS
));
addPreference(new TogglePreference(
context,
"Hide TikTok Shop", "Hide TikTok shop from feed.",
Settings.HIDE_SHOP
));
addPreference(new TogglePreference(
context,
"Hide livestreams", "Hide livestreams from feed.",

View File

@@ -16,9 +16,7 @@ public class SpoofSimPatch {
return false;
}
Logger.initializationException(SpoofSimPatch.class,
"Context is not yet set, cannot spoof: " + fieldSpoofed, null);
Logger.printException(() -> "Context is not yet set, cannot spoof: " + fieldSpoofed, null);
return true;
}

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

View File

@@ -33,4 +33,8 @@ public class Aweme {
public AwemeStatistics getStatistics() {
throw new UnsupportedOperationException("Stub");
}
public String getShareUrl() {
throw new UnsupportedOperationException("Stub");
}
}

View File

@@ -0,0 +1,8 @@
package com.ss.android.ugc.aweme.follow.presenter;
import com.ss.android.ugc.aweme.feed.model.Aweme;
//Dummy class
public class FollowFeed {
public Aweme aweme;
}

View File

@@ -0,0 +1,8 @@
package com.ss.android.ugc.aweme.follow.presenter;
import java.util.List;
//Dummy class
public class FollowFeedList {
public List<FollowFeed> mItems;
}

View File

@@ -1,7 +1,7 @@
android.namespace = "app.revanced.extension"
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

View File

@@ -1,5 +1,5 @@
plugins {
id(libs.plugins.android.library.get().pluginId)
alias(libs.plugins.android.library)
}
android {

Some files were not shown because too many files have changed in this diff Show More