Compare commits

...

67 Commits

Author SHA1 Message Date
semantic-release-bot
77aea074a9 chore: Release v5.2.0-dev.5 [skip ci]
# [5.2.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.4...v5.2.0-dev.5) (2024-11-27)

### Bug Fixes

* **YouTube - Spoof video streams:** Log out the iOS client to restore kids videos playback ([#4000](https://github.com/ReVanced/revanced-patches/issues/4000)) ([fe15213](fe15213cf9))

### Features

* **TikTok:** Add ReVanced settings about screen ([#4009](https://github.com/ReVanced/revanced-patches/issues/4009)) ([046bd3e](046bd3ec88))
2024-11-27 13:35:27 +00:00
oSumAtrIX
fe15213cf9 fix(YouTube - Spoof video streams): Log out the iOS client to restore kids videos playback (#4000) 2024-11-27 14:31:52 +01:00
LisoUseInAIKyrios
046bd3ec88 feat(TikTok): Add ReVanced settings about screen (#4009) 2024-11-27 17:30:55 +04:00
LisoUseInAIKyrios
d6bc998365 chore: Fix spoof version setting migration
Previously this failed because of cyclic initialization of the settings and the spoof version patch
2024-11-27 13:10:22 +04:00
semantic-release-bot
545e16913a chore: Release v5.2.0-dev.4 [skip ci]
# [5.2.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.3...v5.2.0-dev.4) (2024-11-26)

### Bug Fixes

* **YouTube - Playback speed:** Allow long press 2x speed when using custom playback speeds ([#3990](https://github.com/ReVanced/revanced-patches/issues/3990)) ([fafed09](fafed099c5))
2024-11-26 21:16:15 +00:00
LisoUseInAIKyrios
fafed099c5 fix(YouTube - Playback speed): Allow long press 2x speed when using custom playback speeds (#3990) 2024-11-26 22:12:46 +01:00
semantic-release-bot
a65bbebfdb chore: Release v5.2.0-dev.3 [skip ci]
# [5.2.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.2...v5.2.0-dev.3) (2024-11-26)

### Features

* **VSCO:** Remove non functional `Unlock pro` patch ([1a910a2](1a910a2cf6))
2024-11-26 21:06:29 +00:00
oSumAtrIX
1a910a2cf6 feat(VSCO): Remove non functional Unlock pro patch 2024-11-26 22:03:31 +01:00
semantic-release-bot
6d23a4e000 chore: Release v5.2.0-dev.2 [skip ci]
# [5.2.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.1...v5.2.0-dev.2) (2024-11-26)

### Bug Fixes

* **YouTube - Settings:** Show navigation back button in setting sub menus ([#3991](https://github.com/ReVanced/revanced-patches/issues/3991)) ([5c3c684](5c3c68406e))
2024-11-26 16:49:10 +00:00
LisoUseInAIKyrios
5c3c68406e fix(YouTube - Settings): Show navigation back button in setting sub menus (#3991) 2024-11-26 20:45:48 +04:00
github-actions[bot]
b0c3709be7 chore: Sync translations (#3993) 2024-11-26 20:45:18 +04:00
LisoUseInAIKyrios
cd19f976e7 chore: Fix redundant patch description 2024-11-26 16:47:36 +04:00
semantic-release-bot
c181135cc1 chore: Release v5.2.0-dev.1 [skip ci]
# [5.2.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.1.1-dev.2...v5.2.0-dev.1) (2024-11-25)

### Features

* **YouTube - Theme:** Apply custom seekbar color to splash screen animation ([#3978](https://github.com/ReVanced/revanced-patches/issues/3978)) ([7f67759](7f6775950e))
2024-11-25 16:52:34 +00:00
LisoUseInAIKyrios
7f6775950e feat(YouTube - Theme): Apply custom seekbar color to splash screen animation (#3978) 2024-11-25 20:49:05 +04:00
github-actions[bot]
4b2abaf17e chore: Sync translations (#3985) 2024-11-25 20:47:23 +04:00
semantic-release-bot
677b18c41a chore: Release v5.1.1-dev.2 [skip ci]
## [5.1.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.1.1-dev.1...v5.1.1-dev.2) (2024-11-25)

### Bug Fixes

* **YouTube - Hide Shorts components:** Add missing options to patch ([736b6a9](736b6a96b8))
2024-11-25 15:43:26 +00:00
oSumAtrIX
736b6a96b8 fix(YouTube - Hide Shorts components): Add missing options to patch 2024-11-25 16:40:06 +01:00
semantic-release-bot
8c371d8579 chore: Release v5.1.1-dev.1 [skip ci]
## [5.1.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.1.0...v5.1.1-dev.1) (2024-11-24)

### Bug Fixes

* **My Expenses - Unlock pro:** Constrain compatible version to working version ([#3974](https://github.com/ReVanced/revanced-patches/issues/3974)) ([abcaa63](abcaa6336a))
2024-11-24 22:49:39 +00:00
LisoUseInAIKyrios
abcaa6336a fix(My Expenses - Unlock pro): Constrain compatible version to working version (#3974) 2024-11-24 23:47:15 +01:00
semantic-release-bot
11537526a4 chore: Release v5.1.0 [skip ci]
# [5.1.0](https://github.com/ReVanced/revanced-patches/compare/v5.0.2...v5.1.0) (2024-11-24)

### Bug Fixes

* **YouTube - Change header:** Apply header changes to A/B layout ([#3907](https://github.com/ReVanced/revanced-patches/issues/3907)) ([69c504c](69c504ca2f))
* **YouTube - Hide Shorts components:** Do not hide Shorts action buttons on app first launch ([#3933](https://github.com/ReVanced/revanced-patches/issues/3933)) ([c3701c4](c3701c4b6e))
* **YouTube - Playback speed:** Add 'Auto' speed. Always override speed if default is set to 1.0x ([#3914](https://github.com/ReVanced/revanced-patches/issues/3914)) ([78f3fd6](78f3fd6aa4))
* **YouTube - SponsorBlock:** Fix create new segment crash on tablet custom roms ([#3946](https://github.com/ReVanced/revanced-patches/issues/3946)) ([a7fc08a](a7fc08a491))
* **YouTube - Spoof app version:** Adjust legacy spoof targets ([#3934](https://github.com/ReVanced/revanced-patches/issues/3934)) ([2e3b3dc](2e3b3dca4b))
* **YouTube - Spoof app version:** Remove broken spoof targets when patching 19.25+ ([#3915](https://github.com/ReVanced/revanced-patches/issues/3915)) ([17b5b2e](17b5b2e384))

### Features

* **YouTube - Miniplayer:** Add option to disable miniplayer ([#3961](https://github.com/ReVanced/revanced-patches/issues/3961)) ([01cc8e0](01cc8e0abf))
* **YouTube:** Support version `19.45.38` ([#3938](https://github.com/ReVanced/revanced-patches/issues/3938)) ([8c6c8e0](8c6c8e0442))
2024-11-24 04:53:48 +00:00
oSumAtrIX
403116f591 chore: Merge branch dev to main (#3909) 2024-11-24 05:49:58 +01:00
1fexd
a1d14cffe9 chore: Move Sync video downloads patch to correct package 2024-11-24 04:06:02 +04:00
semantic-release-bot
10f221f374 chore: Release v5.1.0-dev.3 [skip ci]
# [5.1.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.1.0-dev.2...v5.1.0-dev.3) (2024-11-22)

### Features

* **YouTube - Miniplayer:** Add option to disable miniplayer ([#3961](https://github.com/ReVanced/revanced-patches/issues/3961)) ([01cc8e0](01cc8e0abf))
2024-11-22 16:44:41 +00:00
github-actions[bot]
ba1aab6d4d chore: Sync translations (#3962) 2024-11-22 20:41:24 +04:00
LisoUseInAIKyrios
01cc8e0abf feat(YouTube - Miniplayer): Add option to disable miniplayer (#3961)
Co-authored-by: oSumAtrIX <johan.melkonyan1@web.de>
2024-11-22 20:37:35 +04:00
LisoUseInAIKyrios
518958350d refactor(YouTube - Announcements): Do not include announcement setting with import/export 2024-11-21 18:48:06 +04:00
semantic-release-bot
a625309d1f chore: Release v5.1.0-dev.2 [skip ci]
# [5.1.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.1.0-dev.1...v5.1.0-dev.2) (2024-11-21)

### Bug Fixes

* **YouTube - SponsorBlock:** Fix create new segment crash on tablet custom roms ([#3946](https://github.com/ReVanced/revanced-patches/issues/3946)) ([a7fc08a](a7fc08a491))
2024-11-21 05:47:29 +00:00
LisoUseInAIKyrios
a7fc08a491 fix(YouTube - SponsorBlock): Fix create new segment crash on tablet custom roms (#3946) 2024-11-21 09:44:32 +04:00
semantic-release-bot
97b129e088 chore: Release v5.1.0-dev.1 [skip ci]
# [5.1.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.5...v5.1.0-dev.1) (2024-11-20)

### Features

* **YouTube:** Support version `19.45.38` ([#3938](https://github.com/ReVanced/revanced-patches/issues/3938)) ([8c6c8e0](8c6c8e0442))
2024-11-20 09:54:50 +00:00
LisoUseInAIKyrios
8c6c8e0442 feat(YouTube): Support version 19.45.38 (#3938) 2024-11-20 13:51:36 +04:00
LisoUseInAIKyrios
16c090d2c0 refactor(YouTube): Use consistent language for 'auto' speed and quality 2024-11-19 11:07:49 +04:00
semantic-release-bot
ed35a2a4a9 chore: Release v5.0.3-dev.5 [skip ci]
## [5.0.3-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.4...v5.0.3-dev.5) (2024-11-18)

### Bug Fixes

* **YouTube - Hide Shorts components:** Do not hide Shorts action buttons on app first launch ([#3933](https://github.com/ReVanced/revanced-patches/issues/3933)) ([c3701c4](c3701c4b6e))
2024-11-18 08:28:49 +00:00
LisoUseInAIKyrios
c3701c4b6e fix(YouTube - Hide Shorts components): Do not hide Shorts action buttons on app first launch (#3933) 2024-11-18 12:25:32 +04:00
github-actions[bot]
e0dc821c50 chore: Sync translations (#3936) 2024-11-18 12:21:46 +04:00
semantic-release-bot
b9efb05271 chore: Release v5.0.3-dev.4 [skip ci]
## [5.0.3-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.3...v5.0.3-dev.4) (2024-11-18)

### Bug Fixes

* **YouTube - Spoof app version:** Adjust legacy spoof targets ([#3934](https://github.com/ReVanced/revanced-patches/issues/3934)) ([2e3b3dc](2e3b3dca4b))
2024-11-18 08:20:28 +00:00
LisoUseInAIKyrios
2e3b3dca4b fix(YouTube - Spoof app version): Adjust legacy spoof targets (#3934) 2024-11-18 12:17:22 +04:00
semantic-release-bot
19eaee09d0 chore: Release v5.0.3-dev.3 [skip ci]
## [5.0.3-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.2...v5.0.3-dev.3) (2024-11-15)

### Bug Fixes

* **YouTube - Playback speed:** Add 'Auto' speed. Always override speed if default is set to 1.0x ([#3914](https://github.com/ReVanced/revanced-patches/issues/3914)) ([78f3fd6](78f3fd6aa4))
2024-11-15 03:59:51 +00:00
LisoUseInAIKyrios
78f3fd6aa4 fix(YouTube - Playback speed): Add 'Auto' speed. Always override speed if default is set to 1.0x (#3914) 2024-11-15 07:56:36 +04:00
semantic-release-bot
71ed37beb1 chore: Release v5.0.3-dev.2 [skip ci]
## [5.0.3-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.1...v5.0.3-dev.2) (2024-11-15)

### Bug Fixes

* **YouTube - Spoof app version:** Remove broken spoof targets when patching 19.25+ ([#3915](https://github.com/ReVanced/revanced-patches/issues/3915)) ([17b5b2e](17b5b2e384))
2024-11-15 03:51:14 +00:00
github-actions[bot]
5aae234c43 chore: Sync translations (#3920) 2024-11-15 07:47:49 +04:00
LisoUseInAIKyrios
17b5b2e384 fix(YouTube - Spoof app version): Remove broken spoof targets when patching 19.25+ (#3915) 2024-11-15 07:44:28 +04:00
LisoUseInAIKyrios
462b61c2e9 refactor(YouTube - Hide mix playlist): Do not search path or buffer unless setting is enabled 2024-11-14 01:37:14 +04:00
semantic-release-bot
f23b7fffc8 chore: Release v5.0.3-dev.1 [skip ci]
## [5.0.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.2...v5.0.3-dev.1) (2024-11-13)

### Bug Fixes

* **YouTube - Change header:** Apply header changes to A/B layout ([#3907](https://github.com/ReVanced/revanced-patches/issues/3907)) ([69c504c](69c504ca2f))
2024-11-13 13:15:15 +00:00
LisoUseInAIKyrios
69c504ca2f fix(YouTube - Change header): Apply header changes to A/B layout (#3907) 2024-11-13 17:12:26 +04:00
semantic-release-bot
fc4b0d7c39 chore: Release v5.0.2 [skip ci]
## [5.0.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.1...v5.0.2) (2024-11-12)

### Bug Fixes

* **Sync for Reddit - Fix /s/ links:** Fix patch by using correct fingerprints ([68ec011](68ec011003))
* **Sync for Reddit - Spoof client:** Fix patch by using correct fingerprints ([273bedc](273bedc74c))
* **YouTube - Player controls:** Show player control buttons with A/B layout ([#3901](https://github.com/ReVanced/revanced-patches/issues/3901)) ([e441745](e4417455c9))
2024-11-12 13:47:36 +00:00
oSumAtrIX
02e66b3d43 chore: Merge branch dev to main (#3899) 2024-11-12 14:44:18 +01:00
semantic-release-bot
a75c15b950 chore: Release v5.0.2-dev.2 [skip ci]
## [5.0.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.2-dev.1...v5.0.2-dev.2) (2024-11-12)

### Bug Fixes

* **YouTube - Player controls:** Show player control buttons with A/B layout ([#3901](https://github.com/ReVanced/revanced-patches/issues/3901)) ([e441745](e4417455c9))
2024-11-12 06:10:45 +00:00
LisoUseInAIKyrios
e4417455c9 fix(YouTube - Player controls): Show player control buttons with A/B layout (#3901) 2024-11-12 10:07:32 +04:00
semantic-release-bot
5253f4bfa4 chore: Release v5.0.2-dev.1 [skip ci]
## [5.0.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.1...v5.0.2-dev.1) (2024-11-11)

### Bug Fixes

* **Sync for Reddit - Fix /s/ links:** Fix patch by using correct fingerprints ([68ec011](68ec011003))
* **Sync for Reddit - Spoof client:** Fix patch by using correct fingerprints ([273bedc](273bedc74c))
2024-11-11 23:57:42 +00:00
oSumAtrIX
273bedc74c fix(Sync for Reddit - Spoof client): Fix patch by using correct fingerprints 2024-11-12 00:55:01 +01:00
oSumAtrIX
68ec011003 fix(Sync for Reddit - Fix /s/ links): Fix patch by using correct fingerprints 2024-11-12 00:44:54 +01:00
semantic-release-bot
f3d1103287 chore: Release v5.0.1 [skip ci]
## [5.0.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.0...v5.0.1) (2024-11-11)

### Bug Fixes

* **Sync:** Fix patches by not throwing unnecessarily ([3059aca](3059aca69d))
* **Tiktok - Settings:** Fix the patch by depending on the correct settings patch ([2094a23](2094a23ccc))
* **Twitter:** Fix patches by depending on patch that merges required extension ([3e1b5cb](3e1b5cbaf5))
* **Twitter:** Fix patches by matching fingerprint using correct class ([3793b21](3793b2103c))
* **YouTube - Playback speed:** Remember playback speed when using non 1.0x default speed ([d881d8b](d881d8bc44)), closes [#3810](https://github.com/ReVanced/revanced-patches/issues/3810)

### Performance Improvements

* Check for extension without a class proxy ([53b6b1f](53b6b1ff41))
2024-11-11 20:42:31 +00:00
oSumAtrIX
50a3541e98 chore: Merge branch dev to main (#3888) 2024-11-11 21:39:55 +01:00
github-actions[bot]
c6069a7ff6 chore: Sync translations (#3897)
Co-authored-by: revanced-bot <github@revanced.app>
2024-11-11 21:39:34 +01:00
semantic-release-bot
b10b624b4b chore: Release v5.0.1-dev.4 [skip ci]
## [5.0.1-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.0.1-dev.3...v5.0.1-dev.4) (2024-11-11)

### Bug Fixes

* **Twitter:** Fix patches by depending on patch that merges required extension ([3e1b5cb](3e1b5cbaf5))
2024-11-11 17:01:35 +00:00
oSumAtrIX
3e1b5cbaf5 fix(Twitter): Fix patches by depending on patch that merges required extension 2024-11-11 17:58:56 +01:00
semantic-release-bot
ef37b78b45 chore: Release v5.0.1-dev.3 [skip ci]
## [5.0.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.0.1-dev.2...v5.0.1-dev.3) (2024-11-11)

### Bug Fixes

* **YouTube - Playback speed:** Remember playback speed when using non 1.0x default speed ([d881d8b](d881d8bc44)), closes [#3810](https://github.com/ReVanced/revanced-patches/issues/3810)
2024-11-11 06:32:25 +00:00
LisoUseInAIKyrios
d881d8bc44 fix(YouTube - Playback speed): Remember playback speed when using non 1.0x default speed
This code was previously present with PR #3810 but was accidentally left out during the DSL migration.
2024-11-11 10:29:15 +04:00
semantic-release-bot
0cb993d6ea chore: Release v5.0.1-dev.2 [skip ci]
## [5.0.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.1-dev.1...v5.0.1-dev.2) (2024-11-11)

### Bug Fixes

* **Twitter:** Fix patches by matching fingerprint using correct class ([3793b21](3793b2103c))
2024-11-11 01:53:03 +00:00
oSumAtrIX
3793b2103c fix(Twitter): Fix patches by matching fingerprint using correct class 2024-11-11 02:50:21 +01:00
semantic-release-bot
658370f035 chore: Release v5.0.1-dev.1 [skip ci]
## [5.0.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.0...v5.0.1-dev.1) (2024-11-11)

### Bug Fixes

* **Sync:** Fix patches by not throwing unnecessarily ([3059aca](3059aca69d))
* **Tiktok - Settings:** Fix the patch by depending on the correct settings patch ([2094a23](2094a23ccc))

### Performance Improvements

* Check for extension without a class proxy ([53b6b1f](53b6b1ff41))
2024-11-11 01:40:33 +00:00
oSumAtrIX
3059aca69d fix(Sync): Fix patches by not throwing unnecessarily 2024-11-11 02:37:44 +01:00
oSumAtrIX
2094a23ccc fix(Tiktok - Settings): Fix the patch by depending on the correct settings patch 2024-11-11 02:33:12 +01:00
oSumAtrIX
53b6b1ff41 perf: Check for extension without a class proxy 2024-11-11 02:25:17 +01:00
semantic-release-bot
5657a7d8c8 chore: Release v5.0.0 [skip ci]
# [5.0.0](https://github.com/ReVanced/revanced-patches/compare/v4.17.0...v5.0.0) (2024-11-10)

### Bug Fixes

* Add missing dependency to patch ([327ebd3](327ebd3649))
* **MyFitnessPal - Hide ads:** Constrain patch to last working version ([#3847](https://github.com/ReVanced/revanced-patches/issues/3847)) ([9c3bec6](9c3bec69d8))
* **Twitter - Change link sharing domain:** Support latest app version ([#3786](https://github.com/ReVanced/revanced-patches/issues/3786)) ([5bdb3a2](5bdb3a2e29))
* **YouTube - Copy video URL:** Support A/B player layout ([c832143](c832143eec))
* **YouTube - Custom branding:** Change icon correctly on 19.34+ ([#3866](https://github.com/ReVanced/revanced-patches/issues/3866)) ([4d1b3fb](4d1b3fba99))
* **YouTube - Hide ads:** Hide new types of ads ([6ceb084](6ceb084831))
* **YouTube - Hide layout components:** Move hide chips settings to Feed menu ([716f0d8](716f0d8d64))
* **YouTube - Hide layout components:** Remove obsolete 'Hide gray separator' ([30a063e](30a063ea12))
* **YouTube - Playback speed:** Remember playback speed with new speed menu ([#3810](https://github.com/ReVanced/revanced-patches/issues/3810)) ([e09b039](e09b03997e))
* **YouTube - Playback speed:** Restore old playback speed menu ([#3817](https://github.com/ReVanced/revanced-patches/issues/3817)) ([1215d16](1215d16a30))
* **YouTube - Remember video quality:** Correctly set default quality when changing from a low quality video ([#3879](https://github.com/ReVanced/revanced-patches/issues/3879)) ([75d661f](75d661fcdc))
* **YouTube - Remove background playback restrictions:** Enable for Shorts as well ([#3671](https://github.com/ReVanced/revanced-patches/issues/3671)) ([a803660](a8036606c1))
* **YouTube - Return YouTube Dislike:** Show Shorts dislikes with new A/B button icons ([a0c227f](a0c227f1a0))
* **YouTube - Return YouTube Dislike:** Use latest separator height ([94adb2e](94adb2eb65))
* **YouTube - Seekbar:** Use latest shade of YouTube red ([e94b216](e94b216e44))
* **YouTube - Settings:** Use multiline preference title for localized languages ([#3821](https://github.com/ReVanced/revanced-patches/issues/3821)) ([2082f14](2082f14f34))
* **YouTube - SponsorBlock:** Show correct segment behavior in settings UI after importing ([53c2f96](53c2f96b6a))
* **YouTube - Spoof app version:** Remove obsolete 17.33.42 spoof target ([#3825](https://github.com/ReVanced/revanced-patches/issues/3825)) ([2165953](2165953a4e))
* **YouTube:** Merge `Restore old seekbar thumbnails` into `Seekbar thumbnails` ([#3860](https://github.com/ReVanced/revanced-patches/issues/3860)) ([042515a](042515a4f0))

### Build System

* Bump ReVanced Patcher ([928cf5f](928cf5f945))

### Features

* **YouTube - Hide layout components:** Hide player shopping shelf ([#3804](https://github.com/ReVanced/revanced-patches/issues/3804)) ([69329df](69329df355))
* **YouTube - Hide player flyout menu items:** Hide stable volume ([#3827](https://github.com/ReVanced/revanced-patches/issues/3827)) ([d3c4811](d3c481166f))
* **YouTube - Miniplayer:** Add horizontal drag gesture ([#3859](https://github.com/ReVanced/revanced-patches/issues/3859)) ([ecf8bd4](ecf8bd445a))
* **YouTube - Player flyout menu:** Hide sleep timer ([#3637](https://github.com/ReVanced/revanced-patches/issues/3637)) ([6348a66](6348a66fef))
* **YouTube:** Add `Seekbar thumbnails` patch ([#3813](https://github.com/ReVanced/revanced-patches/issues/3813)) ([aa2f963](aa2f963e05))
* **YouTube:** Add `Shorts autoplay` patch ([#3794](https://github.com/ReVanced/revanced-patches/issues/3794)) ([132d925](132d925d5c))
* **YouTube:** Hide player shopping shelf in playlists ([#3806](https://github.com/ReVanced/revanced-patches/issues/3806)) ([68d9edf](68d9edfd8c))
* **YouTube:** Merge multiple layout patches into `Hide Layout Components` ([#3799](https://github.com/ReVanced/revanced-patches/issues/3799)) ([24d612d](24d612d0d1))
* **YouTube:** Merge multiple player overlay patches into `Hide player overlay buttons` ([#3800](https://github.com/ReVanced/revanced-patches/issues/3800)) ([cee0641](cee0641247))
* **YouTube:** Support version `19.43.41` ([#3854](https://github.com/ReVanced/revanced-patches/issues/3854)) ([43f5e99](43f5e99e0b))

### BREAKING CHANGES

* Various APIs have been changed or removed.
2024-11-10 14:59:53 +00:00
oSumAtrIX
08ce458e28 chore: Merge branch dev to main (#3798) 2024-11-10 15:56:12 +01:00
github-actions[bot]
b5e4022fbb chore: Sync translations (#3881)
Co-authored-by: revanced-bot <github@revanced.app>
2024-11-10 15:48:08 +01:00
210 changed files with 3433 additions and 2039 deletions

View File

@@ -1,3 +1,254 @@
# [5.2.0-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.4...v5.2.0-dev.5) (2024-11-27)
### Bug Fixes
* **YouTube - Spoof video streams:** Log out the iOS client to restore kids videos playback ([#4000](https://github.com/ReVanced/revanced-patches/issues/4000)) ([cc2ac4e](https://github.com/ReVanced/revanced-patches/commit/cc2ac4e4cd15ca2a23d60abd160d915bc98f99b4))
### Features
* **TikTok:** Add ReVanced settings about screen ([#4009](https://github.com/ReVanced/revanced-patches/issues/4009)) ([12ea26b](https://github.com/ReVanced/revanced-patches/commit/12ea26b10ddea5ad39da1d35e2b8fd0b48c15d88))
# [5.2.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.3...v5.2.0-dev.4) (2024-11-26)
### Bug Fixes
* **YouTube - Playback speed:** Allow long press 2x speed when using custom playback speeds ([#3990](https://github.com/ReVanced/revanced-patches/issues/3990)) ([79a543a](https://github.com/ReVanced/revanced-patches/commit/79a543a57470638f983862c61270e046f3ac5cb7))
# [5.2.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.2...v5.2.0-dev.3) (2024-11-26)
### Features
* **VSCO:** Remove non functional `Unlock pro` patch ([4fddb19](https://github.com/ReVanced/revanced-patches/commit/4fddb1930bc7adeee3b60ae9cd346b143e88bd42))
# [5.2.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.2.0-dev.1...v5.2.0-dev.2) (2024-11-26)
### Bug Fixes
* **YouTube - Settings:** Show navigation back button in setting sub menus ([#3991](https://github.com/ReVanced/revanced-patches/issues/3991)) ([e61686c](https://github.com/ReVanced/revanced-patches/commit/e61686c1039ae29e443273e4da4ec63956216841))
# [5.2.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.1.1-dev.2...v5.2.0-dev.1) (2024-11-25)
### Features
* **YouTube - Theme:** Apply custom seekbar color to splash screen animation ([#3978](https://github.com/ReVanced/revanced-patches/issues/3978)) ([98d57e2](https://github.com/ReVanced/revanced-patches/commit/98d57e28af7206099867474b7aa3760cd4fe333f))
## [5.1.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.1.1-dev.1...v5.1.1-dev.2) (2024-11-25)
### Bug Fixes
* **YouTube - Hide Shorts components:** Add missing options to patch ([65f62fc](https://github.com/ReVanced/revanced-patches/commit/65f62fcd5ac340616a96542c64faf2af2a60df28))
## [5.1.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.1.0...v5.1.1-dev.1) (2024-11-24)
### Bug Fixes
* **My Expenses - Unlock pro:** Constrain compatible version to working version ([#3974](https://github.com/ReVanced/revanced-patches/issues/3974)) ([ba3bf69](https://github.com/ReVanced/revanced-patches/commit/ba3bf69df07ec8dab46868c3940ebd56db0cd137))
# [5.1.0](https://github.com/ReVanced/revanced-patches/compare/v5.0.2...v5.1.0) (2024-11-24)
### Bug Fixes
* **YouTube - Change header:** Apply header changes to A/B layout ([#3907](https://github.com/ReVanced/revanced-patches/issues/3907)) ([6ccf114](https://github.com/ReVanced/revanced-patches/commit/6ccf11426ec9e9cd9c8e89a2443f0d0645cc78b1))
* **YouTube - Hide Shorts components:** Do not hide Shorts action buttons on app first launch ([#3933](https://github.com/ReVanced/revanced-patches/issues/3933)) ([0d78815](https://github.com/ReVanced/revanced-patches/commit/0d78815e33bf2ae216e519f067fb773df0f2084e))
* **YouTube - Playback speed:** Add 'Auto' speed. Always override speed if default is set to 1.0x ([#3914](https://github.com/ReVanced/revanced-patches/issues/3914)) ([497739e](https://github.com/ReVanced/revanced-patches/commit/497739e8ce6933c1f1ea46edffc102e56b985623))
* **YouTube - SponsorBlock:** Fix create new segment crash on tablet custom roms ([#3946](https://github.com/ReVanced/revanced-patches/issues/3946)) ([a0da377](https://github.com/ReVanced/revanced-patches/commit/a0da377ba8f90ba39e905ed9730b3e819633bd50))
* **YouTube - Spoof app version:** Adjust legacy spoof targets ([#3934](https://github.com/ReVanced/revanced-patches/issues/3934)) ([f5794c1](https://github.com/ReVanced/revanced-patches/commit/f5794c1f896c331d76fdfc299e31a2773f2209ca))
* **YouTube - Spoof app version:** Remove broken spoof targets when patching 19.25+ ([#3915](https://github.com/ReVanced/revanced-patches/issues/3915)) ([9e18eca](https://github.com/ReVanced/revanced-patches/commit/9e18ecab1877dd33a3ad0fe216e6b91a8daaf1f8))
### Features
* **YouTube - Miniplayer:** Add option to disable miniplayer ([#3961](https://github.com/ReVanced/revanced-patches/issues/3961)) ([e565cdb](https://github.com/ReVanced/revanced-patches/commit/e565cdb583aacfc0052d12c430f56fd9abd5bf00))
* **YouTube:** Support version `19.45.38` ([#3938](https://github.com/ReVanced/revanced-patches/issues/3938)) ([7c4e3fe](https://github.com/ReVanced/revanced-patches/commit/7c4e3fe97e8cbbb8cf16a2fb95f64223ca2bd7ef))
# [5.1.0-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.1.0-dev.2...v5.1.0-dev.3) (2024-11-22)
### Features
* **YouTube - Miniplayer:** Add option to disable miniplayer ([#3961](https://github.com/ReVanced/revanced-patches/issues/3961)) ([e565cdb](https://github.com/ReVanced/revanced-patches/commit/e565cdb583aacfc0052d12c430f56fd9abd5bf00))
# [5.1.0-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.1.0-dev.1...v5.1.0-dev.2) (2024-11-21)
### Bug Fixes
* **YouTube - SponsorBlock:** Fix create new segment crash on tablet custom roms ([#3946](https://github.com/ReVanced/revanced-patches/issues/3946)) ([a0da377](https://github.com/ReVanced/revanced-patches/commit/a0da377ba8f90ba39e905ed9730b3e819633bd50))
# [5.1.0-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.5...v5.1.0-dev.1) (2024-11-20)
### Features
* **YouTube:** Support version `19.45.38` ([#3938](https://github.com/ReVanced/revanced-patches/issues/3938)) ([7c4e3fe](https://github.com/ReVanced/revanced-patches/commit/7c4e3fe97e8cbbb8cf16a2fb95f64223ca2bd7ef))
## [5.0.3-dev.5](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.4...v5.0.3-dev.5) (2024-11-18)
### Bug Fixes
* **YouTube - Hide Shorts components:** Do not hide Shorts action buttons on app first launch ([#3933](https://github.com/ReVanced/revanced-patches/issues/3933)) ([0d78815](https://github.com/ReVanced/revanced-patches/commit/0d78815e33bf2ae216e519f067fb773df0f2084e))
## [5.0.3-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.3...v5.0.3-dev.4) (2024-11-18)
### Bug Fixes
* **YouTube - Spoof app version:** Adjust legacy spoof targets ([#3934](https://github.com/ReVanced/revanced-patches/issues/3934)) ([f5794c1](https://github.com/ReVanced/revanced-patches/commit/f5794c1f896c331d76fdfc299e31a2773f2209ca))
## [5.0.3-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.2...v5.0.3-dev.3) (2024-11-15)
### Bug Fixes
* **YouTube - Playback speed:** Add 'Auto' speed. Always override speed if default is set to 1.0x ([#3914](https://github.com/ReVanced/revanced-patches/issues/3914)) ([497739e](https://github.com/ReVanced/revanced-patches/commit/497739e8ce6933c1f1ea46edffc102e56b985623))
## [5.0.3-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.3-dev.1...v5.0.3-dev.2) (2024-11-15)
### Bug Fixes
* **YouTube - Spoof app version:** Remove broken spoof targets when patching 19.25+ ([#3915](https://github.com/ReVanced/revanced-patches/issues/3915)) ([9e18eca](https://github.com/ReVanced/revanced-patches/commit/9e18ecab1877dd33a3ad0fe216e6b91a8daaf1f8))
## [5.0.3-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.2...v5.0.3-dev.1) (2024-11-13)
### Bug Fixes
* **YouTube - Change header:** Apply header changes to A/B layout ([#3907](https://github.com/ReVanced/revanced-patches/issues/3907)) ([6ccf114](https://github.com/ReVanced/revanced-patches/commit/6ccf11426ec9e9cd9c8e89a2443f0d0645cc78b1))
## [5.0.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.1...v5.0.2) (2024-11-12)
### Bug Fixes
* **Sync for Reddit - Fix /s/ links:** Fix patch by using correct fingerprints ([a0ad07e](https://github.com/ReVanced/revanced-patches/commit/a0ad07ef3170dbe1d91ebd40f11d97b63d1c63d0))
* **Sync for Reddit - Spoof client:** Fix patch by using correct fingerprints ([5776de3](https://github.com/ReVanced/revanced-patches/commit/5776de3cfbfa62360267eb6026525d2da8c45654))
* **YouTube - Player controls:** Show player control buttons with A/B layout ([#3901](https://github.com/ReVanced/revanced-patches/issues/3901)) ([bb526bc](https://github.com/ReVanced/revanced-patches/commit/bb526bc00a384eb808f46267e5802c8e5beaa7d5))
## [5.0.2-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.2-dev.1...v5.0.2-dev.2) (2024-11-12)
### Bug Fixes
* **YouTube - Player controls:** Show player control buttons with A/B layout ([#3901](https://github.com/ReVanced/revanced-patches/issues/3901)) ([bb526bc](https://github.com/ReVanced/revanced-patches/commit/bb526bc00a384eb808f46267e5802c8e5beaa7d5))
## [5.0.2-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.1...v5.0.2-dev.1) (2024-11-11)
### Bug Fixes
* **Sync for Reddit - Fix /s/ links:** Fix patch by using correct fingerprints ([a0ad07e](https://github.com/ReVanced/revanced-patches/commit/a0ad07ef3170dbe1d91ebd40f11d97b63d1c63d0))
* **Sync for Reddit - Spoof client:** Fix patch by using correct fingerprints ([5776de3](https://github.com/ReVanced/revanced-patches/commit/5776de3cfbfa62360267eb6026525d2da8c45654))
## [5.0.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.0...v5.0.1) (2024-11-11)
### Bug Fixes
* **Sync:** Fix patches by not throwing unnecessarily ([2ee1316](https://github.com/ReVanced/revanced-patches/commit/2ee13160d51dba3c5806594b2387f806e5946b9a))
* **Tiktok - Settings:** Fix the patch by depending on the correct settings patch ([0c75929](https://github.com/ReVanced/revanced-patches/commit/0c75929a83729841197b482d28f7f7f5f9cec332))
* **Twitter:** Fix patches by depending on patch that merges required extension ([c330e9d](https://github.com/ReVanced/revanced-patches/commit/c330e9d67d3e8c8c3535fa43e52c9f06e33ff0bf))
* **Twitter:** Fix patches by matching fingerprint using correct class ([6ae0d12](https://github.com/ReVanced/revanced-patches/commit/6ae0d124e1f27faecd20e4008951b08353572d98))
* **YouTube - Playback speed:** Remember playback speed when using non 1.0x default speed ([05b9f87](https://github.com/ReVanced/revanced-patches/commit/05b9f8709895dae67e8cc12e8b7bdb87ff401997)), closes [#3810](https://github.com/ReVanced/revanced-patches/issues/3810)
### Performance Improvements
* Check for extension without a class proxy ([a6a74e2](https://github.com/ReVanced/revanced-patches/commit/a6a74e289db1fe04db230d1e864cb9e752f9a01d))
## [5.0.1-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.0.1-dev.3...v5.0.1-dev.4) (2024-11-11)
### Bug Fixes
* **Twitter:** Fix patches by depending on patch that merges required extension ([c330e9d](https://github.com/ReVanced/revanced-patches/commit/c330e9d67d3e8c8c3535fa43e52c9f06e33ff0bf))
## [5.0.1-dev.3](https://github.com/ReVanced/revanced-patches/compare/v5.0.1-dev.2...v5.0.1-dev.3) (2024-11-11)
### Bug Fixes
* **YouTube - Playback speed:** Remember playback speed when using non 1.0x default speed ([05b9f87](https://github.com/ReVanced/revanced-patches/commit/05b9f8709895dae67e8cc12e8b7bdb87ff401997)), closes [#3810](https://github.com/ReVanced/revanced-patches/issues/3810)
## [5.0.1-dev.2](https://github.com/ReVanced/revanced-patches/compare/v5.0.1-dev.1...v5.0.1-dev.2) (2024-11-11)
### Bug Fixes
* **Twitter:** Fix patches by matching fingerprint using correct class ([6ae0d12](https://github.com/ReVanced/revanced-patches/commit/6ae0d124e1f27faecd20e4008951b08353572d98))
## [5.0.1-dev.1](https://github.com/ReVanced/revanced-patches/compare/v5.0.0...v5.0.1-dev.1) (2024-11-11)
### Bug Fixes
* **Sync:** Fix patches by not throwing unnecessarily ([2ee1316](https://github.com/ReVanced/revanced-patches/commit/2ee13160d51dba3c5806594b2387f806e5946b9a))
* **Tiktok - Settings:** Fix the patch by depending on the correct settings patch ([0c75929](https://github.com/ReVanced/revanced-patches/commit/0c75929a83729841197b482d28f7f7f5f9cec332))
### Performance Improvements
* Check for extension without a class proxy ([a6a74e2](https://github.com/ReVanced/revanced-patches/commit/a6a74e289db1fe04db230d1e864cb9e752f9a01d))
# [5.0.0](https://github.com/ReVanced/revanced-patches/compare/v4.17.0...v5.0.0) (2024-11-10)
### Bug Fixes
* Add missing dependency to patch ([97f5240](https://github.com/ReVanced/revanced-patches/commit/97f5240d53b9978fb3745170fe03619c7c90274a))
* **MyFitnessPal - Hide ads:** Constrain patch to last working version ([#3847](https://github.com/ReVanced/revanced-patches/issues/3847)) ([f9fa526](https://github.com/ReVanced/revanced-patches/commit/f9fa526b04c2848175c389d6bb911aa5a245b60f))
* **Twitter - Change link sharing domain:** Support latest app version ([#3786](https://github.com/ReVanced/revanced-patches/issues/3786)) ([b54592c](https://github.com/ReVanced/revanced-patches/commit/b54592cf9c5d859e1af2f02e8e6aaad7d47ab760))
* **YouTube - Copy video URL:** Support A/B player layout ([0f42574](https://github.com/ReVanced/revanced-patches/commit/0f42574b7f4b1c9a48df8550c7d710093f76ce8c))
* **YouTube - Custom branding:** Change icon correctly on 19.34+ ([#3866](https://github.com/ReVanced/revanced-patches/issues/3866)) ([2e47903](https://github.com/ReVanced/revanced-patches/commit/2e4790382546256e106a5842cd8c530f41b161e5))
* **YouTube - Hide ads:** Hide new types of ads ([454281a](https://github.com/ReVanced/revanced-patches/commit/454281ac2108648832b7f0203f5fb7e814887835))
* **YouTube - Hide layout components:** Move hide chips settings to Feed menu ([1ed677f](https://github.com/ReVanced/revanced-patches/commit/1ed677f7b8ba561b2bb173dcaf5d6123c22179c4))
* **YouTube - Hide layout components:** Remove obsolete 'Hide gray separator' ([a697701](https://github.com/ReVanced/revanced-patches/commit/a697701c5f1f9510b51e310b1ff212b609f38519))
* **YouTube - Playback speed:** Remember playback speed with new speed menu ([#3810](https://github.com/ReVanced/revanced-patches/issues/3810)) ([c3a5e14](https://github.com/ReVanced/revanced-patches/commit/c3a5e14a0a24973a0f9956845c9e0f99c1301d42))
* **YouTube - Playback speed:** Restore old playback speed menu ([#3817](https://github.com/ReVanced/revanced-patches/issues/3817)) ([806b210](https://github.com/ReVanced/revanced-patches/commit/806b21093e3251697f03cd8804e5d5cd26070716))
* **YouTube - Remember video quality:** Correctly set default quality when changing from a low quality video ([#3879](https://github.com/ReVanced/revanced-patches/issues/3879)) ([ddb73e8](https://github.com/ReVanced/revanced-patches/commit/ddb73e857d7c26fd27ea995a27f53f5660d3f71c))
* **YouTube - Remove background playback restrictions:** Enable for Shorts as well ([#3671](https://github.com/ReVanced/revanced-patches/issues/3671)) ([7db1a77](https://github.com/ReVanced/revanced-patches/commit/7db1a7751dc47c4e36096fbdc2b3761b0ae11ccb))
* **YouTube - Return YouTube Dislike:** Show Shorts dislikes with new A/B button icons ([084e0a5](https://github.com/ReVanced/revanced-patches/commit/084e0a527b1c75d1ef15dc706c429aa48d0ffe6b))
* **YouTube - Return YouTube Dislike:** Use latest separator height ([ae160a3](https://github.com/ReVanced/revanced-patches/commit/ae160a37985cc96c6de7e1a2fe5a1c83bc523046))
* **YouTube - Seekbar:** Use latest shade of YouTube red ([4b77648](https://github.com/ReVanced/revanced-patches/commit/4b77648607a84eb29f4cae9ddb42b87084be7cd0))
* **YouTube - Settings:** Use multiline preference title for localized languages ([#3821](https://github.com/ReVanced/revanced-patches/issues/3821)) ([ff85d49](https://github.com/ReVanced/revanced-patches/commit/ff85d490887de64eb6c6fd42e385a3e75969ff10))
* **YouTube - SponsorBlock:** Show correct segment behavior in settings UI after importing ([e3f25a0](https://github.com/ReVanced/revanced-patches/commit/e3f25a03cd314eeae786e7660a6beacb275a6a76))
* **YouTube - Spoof app version:** Remove obsolete 17.33.42 spoof target ([#3825](https://github.com/ReVanced/revanced-patches/issues/3825)) ([33aeba2](https://github.com/ReVanced/revanced-patches/commit/33aeba2a0895e9ecaba27ba4a3b22b86c9f1a51c))
* **YouTube:** Merge `Restore old seekbar thumbnails` into `Seekbar thumbnails` ([#3860](https://github.com/ReVanced/revanced-patches/issues/3860)) ([e377b1e](https://github.com/ReVanced/revanced-patches/commit/e377b1e6ad93dea8e5f3829cd3894f71851887a3))
### Build System
* Bump ReVanced Patcher ([eee1692](https://github.com/ReVanced/revanced-patches/commit/eee16922779f994f5752190a20a9016ea98ec4cb))
### Features
* **YouTube - Hide layout components:** Hide player shopping shelf ([#3804](https://github.com/ReVanced/revanced-patches/issues/3804)) ([1952f3b](https://github.com/ReVanced/revanced-patches/commit/1952f3b3c4bca08ed0f6e5b1117e0a6c51f00ed2))
* **YouTube - Hide player flyout menu items:** Hide stable volume ([#3827](https://github.com/ReVanced/revanced-patches/issues/3827)) ([b91e932](https://github.com/ReVanced/revanced-patches/commit/b91e932e65c04b1c1aee9a2f3dc3a73772d9c225))
* **YouTube - Miniplayer:** Add horizontal drag gesture ([#3859](https://github.com/ReVanced/revanced-patches/issues/3859)) ([e32b19e](https://github.com/ReVanced/revanced-patches/commit/e32b19e170a5571b23547c3211b497089d0cd441))
* **YouTube - Player flyout menu:** Hide sleep timer ([#3637](https://github.com/ReVanced/revanced-patches/issues/3637)) ([7e1bdab](https://github.com/ReVanced/revanced-patches/commit/7e1bdab520dba65682f018f819c0b7d9783f94ca))
* **YouTube:** Add `Seekbar thumbnails` patch ([#3813](https://github.com/ReVanced/revanced-patches/issues/3813)) ([5988b75](https://github.com/ReVanced/revanced-patches/commit/5988b759752b944b6999b401faa394e2089e4003))
* **YouTube:** Add `Shorts autoplay` patch ([#3794](https://github.com/ReVanced/revanced-patches/issues/3794)) ([96b5aed](https://github.com/ReVanced/revanced-patches/commit/96b5aede482f7a69d6df17864a2e17568b0da880))
* **YouTube:** Hide player shopping shelf in playlists ([#3806](https://github.com/ReVanced/revanced-patches/issues/3806)) ([a553a13](https://github.com/ReVanced/revanced-patches/commit/a553a13c0326ef2fff7f785fed592d553a7963ce))
* **YouTube:** Merge multiple layout patches into `Hide Layout Components` ([#3799](https://github.com/ReVanced/revanced-patches/issues/3799)) ([bbcb57a](https://github.com/ReVanced/revanced-patches/commit/bbcb57a32dfc8f031886f98b1b9701285105c579))
* **YouTube:** Merge multiple player overlay patches into `Hide player overlay buttons` ([#3800](https://github.com/ReVanced/revanced-patches/issues/3800)) ([4ba0300](https://github.com/ReVanced/revanced-patches/commit/4ba0300590dd988bdcaa0761c4e606c1d7f86ce5))
* **YouTube:** Support version `19.43.41` ([#3854](https://github.com/ReVanced/revanced-patches/issues/3854)) ([85de5c7](https://github.com/ReVanced/revanced-patches/commit/85de5c7d96ce2d67f6386d1438e43620d31cc645))
### BREAKING CHANGES
* Various APIs have been changed or removed.
# [5.0.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.0.0-dev.3...v5.0.0-dev.4) (2024-11-09) # [5.0.0-dev.4](https://github.com/ReVanced/revanced-patches/compare/v5.0.0-dev.3...v5.0.0-dev.4) (2024-11-09)

View File

@@ -1,7 +1,11 @@
package app.revanced.extension.shared.checks; package app.revanced.extension.shared.checks;
// Fields are set by the patch. Do not modify. /**
// Fields are not final, because the compiler is inlining them. * Fields are set by the patch. Do not modify.
* Fields are not final, because the compiler is inlining them.
*
* @noinspection CanBeFinal
*/
final class PatchInfo { final class PatchInfo {
static long PATCH_TIME = 0L; static long PATCH_TIME = 0L;

View File

@@ -1,21 +1,33 @@
package app.revanced.extension.shared.settings.preference; package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.*; import android.preference.*;
import android.util.TypedValue;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toolbar;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.util.Objects;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.BooleanSetting; import app.revanced.extension.shared.settings.BooleanSetting;
import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.youtube.ThemeHelper;
import static app.revanced.extension.shared.StringRef.str;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public abstract class AbstractPreferenceFragment extends PreferenceFragment { public abstract class AbstractPreferenceFragment extends PreferenceFragment {
@@ -71,6 +83,15 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
} }
}; };
@SuppressLint("UseCompatLoadingForDrawables")
public static Drawable getBackButtonDrawable() {
final int backButtonResource = getResourceIdentifier(ThemeHelper.isDarkTheme()
? "yt_outline_arrow_left_white_24"
: "yt_outline_arrow_left_black_24",
"drawable");
return Utils.getContext().getResources().getDrawable(backButtonResource);
}
/** /**
* Initialize this instance, and do any custom behavior. * Initialize this instance, and do any custom behavior.
* <p> * <p>
@@ -98,7 +119,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
showingUserDialogMessage = true; showingUserDialogMessage = true;
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setTitle(confirmDialogTitle) .setTitle(confirmDialogTitle)
.setMessage(setting.userDialogMessage.toString()) .setMessage(Objects.requireNonNull(setting.userDialogMessage).toString())
.setPositiveButton(android.R.string.ok, (dialog, id) -> { .setPositiveButton(android.R.string.ok, (dialog, id) -> {
if (setting.rebootApp) { if (setting.rebootApp) {
showRestartDialog(context); showRestartDialog(context);
@@ -261,6 +282,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
// causes a callback to the listener even though nothing changed. // causes a callback to the listener even though nothing changed.
initialize(); initialize();
updateUIToSettingValues(); updateUIToSettingValues();
setPreferenceScreenToolbar(getPreferenceScreen());
preferenceManager.getSharedPreferences().registerOnSharedPreferenceChangeListener(listener); preferenceManager.getSharedPreferences().registerOnSharedPreferenceChangeListener(listener);
} catch (Exception ex) { } catch (Exception ex) {
@@ -273,4 +295,44 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener); getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
super.onDestroy(); super.onDestroy();
} }
private void setPreferenceScreenToolbar(PreferenceScreen parentScreen) {
for (int i = 0, preferenceCount = parentScreen.getPreferenceCount(); i < preferenceCount; i++) {
Preference childPreference = parentScreen.getPreference(i);
if (childPreference instanceof PreferenceScreen) {
// Recursively set sub preferences.
setPreferenceScreenToolbar((PreferenceScreen) childPreference);
childPreference.setOnPreferenceClickListener(
childScreen -> {
Dialog preferenceScreenDialog = ((PreferenceScreen) childScreen).getDialog();
ViewGroup rootView = (ViewGroup) preferenceScreenDialog
.findViewById(android.R.id.content)
.getParent();
Toolbar toolbar = new Toolbar(childScreen.getContext());
toolbar.setTitle(childScreen.getTitle());
toolbar.setNavigationIcon(getBackButtonDrawable());
toolbar.setNavigationOnClickListener(view -> preferenceScreenDialog.dismiss());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
final int margin = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 16, getResources().getDisplayMetrics()
);
toolbar.setTitleMargin(margin, 0, margin, 0);
}
TextView toolbarTextView = Utils.getChildView(toolbar,
true, TextView.class::isInstance);
if (toolbarTextView != null) {
toolbarTextView.setTextColor(ThemeHelper.getForegroundColor());
}
rootView.addView(toolbar, 0);
return false;
}
);
}
}
}
} }

View File

@@ -1,6 +1,5 @@
package app.revanced.extension.shared.settings.preference; package app.revanced.extension.shared.settings.preference;
import static app.revanced.extension.shared.StringRef.sf;
import static app.revanced.extension.shared.StringRef.str; import static app.revanced.extension.shared.StringRef.str;
import static app.revanced.extension.youtube.requests.Route.Method.GET; import static app.revanced.extension.youtube.requests.Route.Method.GET;
@@ -13,6 +12,8 @@ import android.content.res.Configuration;
import android.graphics.Color; import android.graphics.Color;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.preference.Preference; import android.preference.Preference;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Window; import android.view.Window;
@@ -37,7 +38,7 @@ import app.revanced.extension.youtube.requests.Requester;
import app.revanced.extension.youtube.requests.Route; import app.revanced.extension.youtube.requests.Route;
/** /**
* Opens a dialog showing the links from {@link SocialLinksRoutes}. * Opens a dialog showing official links.
*/ */
@SuppressWarnings({"unused", "deprecation"}) @SuppressWarnings({"unused", "deprecation"})
public class ReVancedAboutPreference extends Preference { public class ReVancedAboutPreference extends Preference {
@@ -72,7 +73,16 @@ public class ReVancedAboutPreference extends Preference {
return Color.BLACK; return Color.BLACK;
} }
private String createDialogHtml(WebLink[] socialLinks) { /**
* Apps that do not support bundling resources must override this.
*
* @return A localized string to display for the key.
*/
protected String getString(String key, Object ... args) {
return str(key, args);
}
private String createDialogHtml(WebLink[] aboutLinks) {
final boolean isNetworkConnected = Utils.isNetworkConnected(); final boolean isNetworkConnected = Utils.isNetworkConnected();
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
@@ -91,7 +101,7 @@ public class ReVancedAboutPreference extends Preference {
builder.append("<img style=\"width: 100px; height: 100px;\" " builder.append("<img style=\"width: 100px; height: 100px;\" "
// Hide the image if it does not load. // Hide the image if it does not load.
+ "onerror=\"this.style.display='none';\" " + "onerror=\"this.style.display='none';\" "
+ "src=\"https://revanced.app/favicon.ico\" />"); + "src=\"").append(AboutLinksRoutes.aboutLogoUrl).append("\" />");
} }
String patchesVersion = Utils.getPatchesReleaseVersion(); String patchesVersion = Utils.getPatchesReleaseVersion();
@@ -103,29 +113,29 @@ public class ReVancedAboutPreference extends Preference {
builder.append("<p>") builder.append("<p>")
// Replace hyphens with non breaking dashes so the version number does not break lines. // Replace hyphens with non breaking dashes so the version number does not break lines.
.append(useNonBreakingHyphens(str("revanced_settings_about_links_body", patchesVersion))) .append(useNonBreakingHyphens(getString("revanced_settings_about_links_body", patchesVersion)))
.append("</p>"); .append("</p>");
// Add a disclaimer if using a dev release. // Add a disclaimer if using a dev release.
if (patchesVersion.contains("dev")) { if (patchesVersion.contains("dev")) {
builder.append("<h3>") builder.append("<h3>")
// English text 'Pre-release' can break lines. // English text 'Pre-release' can break lines.
.append(useNonBreakingHyphens(str("revanced_settings_about_links_dev_header"))) .append(useNonBreakingHyphens(getString("revanced_settings_about_links_dev_header")))
.append("</h3>"); .append("</h3>");
builder.append("<p>") builder.append("<p>")
.append(str("revanced_settings_about_links_dev_body")) .append(getString("revanced_settings_about_links_dev_body"))
.append("</p>"); .append("</p>");
} }
builder.append("<h2 style=\"margin-top: 30px;\">") builder.append("<h2 style=\"margin-top: 30px;\">")
.append(str("revanced_settings_about_links_header")) .append(getString("revanced_settings_about_links_header"))
.append("</h2>"); .append("</h2>");
builder.append("<div>"); builder.append("<div>");
for (WebLink social : socialLinks) { for (WebLink link : aboutLinks) {
builder.append("<div style=\"margin-bottom: 20px;\">"); builder.append("<div style=\"margin-bottom: 20px;\">");
builder.append(String.format("<a href=\"%s\">%s</a>", social.url, social.name)); builder.append(String.format("<a href=\"%s\">%s</a>", link.url, link.name));
builder.append("</div>"); builder.append("</div>");
} }
builder.append("</div>"); builder.append("</div>");
@@ -137,25 +147,44 @@ public class ReVancedAboutPreference extends Preference {
{ {
setOnPreferenceClickListener(pref -> { setOnPreferenceClickListener(pref -> {
// Show a progress spinner if the social links are not fetched yet. // Show a progress spinner if the social links are not fetched yet.
if (!SocialLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) { if (!AboutLinksRoutes.hasFetchedLinks() && Utils.isNetworkConnected()) {
// Show a progress spinner, but only if the api fetch takes more than a half a second.
final long delayToShowProgressSpinner = 500;
ProgressDialog progress = new ProgressDialog(getContext()); ProgressDialog progress = new ProgressDialog(getContext());
progress.setProgressStyle(ProgressDialog.STYLE_SPINNER); progress.setProgressStyle(ProgressDialog.STYLE_SPINNER);
progress.show();
Utils.runOnBackgroundThread(() -> fetchLinksAndShowDialog(progress)); Handler handler = new Handler(Looper.getMainLooper());
Runnable showDialogRunnable = progress::show;
handler.postDelayed(showDialogRunnable, delayToShowProgressSpinner);
Utils.runOnBackgroundThread(() ->
fetchLinksAndShowDialog(handler, showDialogRunnable, progress));
} else { } else {
// No network call required and can run now. // No network call required and can run now.
fetchLinksAndShowDialog(null); fetchLinksAndShowDialog(null, null, null);
} }
return false; return false;
}); });
} }
private void fetchLinksAndShowDialog(@Nullable ProgressDialog progress) { private void fetchLinksAndShowDialog(@Nullable Handler handler,
WebLink[] socialLinks = SocialLinksRoutes.fetchSocialLinks(); Runnable showDialogRunnable,
String htmlDialog = createDialogHtml(socialLinks); @Nullable ProgressDialog progress) {
WebLink[] links = AboutLinksRoutes.fetchAboutLinks();
String htmlDialog = createDialogHtml(links);
// Enable to randomly force a delay to debug the spinner logic.
final boolean debugSpinnerDelayLogic = false;
//noinspection ConstantConditions
if (debugSpinnerDelayLogic && handler != null && Math.random() < 0.5f) {
Utils.doNothingForDuration((long) (Math.random() * 4000));
}
Utils.runOnMainThreadNowOrLater(() -> { Utils.runOnMainThreadNowOrLater(() -> {
if (handler != null) {
handler.removeCallbacks(showDialogRunnable);
}
if (progress != null) { if (progress != null) {
progress.dismiss(); progress.dismiss();
} }
@@ -224,7 +253,7 @@ class WebViewDialog extends Dialog {
class WebLink { class WebLink {
final boolean preferred; final boolean preferred;
final String name; String name;
final String url; final String url;
WebLink(JSONObject json) throws JSONException { WebLink(JSONObject json) throws JSONException {
@@ -243,7 +272,7 @@ class WebLink {
@NonNull @NonNull
@Override @Override
public String toString() { public String toString() {
return "ReVancedSocialLink{" + return "WebLink{" +
"preferred=" + preferred + "preferred=" + preferred +
", name='" + name + '\'' + ", name='" + name + '\'' +
", url='" + url + '\'' + ", url='" + url + '\'' +
@@ -251,25 +280,21 @@ class WebLink {
} }
} }
class SocialLinksRoutes { class AboutLinksRoutes {
/** /**
* Simple link to the website donate page, * Backup icon url if the API call fails.
* rather than fetching and parsing the donation links using the API.
*/ */
public static final WebLink DONATE_LINK = new WebLink(true, public static volatile String aboutLogoUrl = "https://revanced.app/favicon.ico";
sf("revanced_settings_about_links_donate").toString(),
"https://revanced.app/donate");
/** /**
* Links to use if fetch links api call fails. * Links to use if fetch links api call fails.
*/ */
private static final WebLink[] NO_CONNECTION_STATIC_LINKS = { private static final WebLink[] NO_CONNECTION_STATIC_LINKS = {
new WebLink(true, "ReVanced.app", "https://revanced.app"), new WebLink(true, "ReVanced.app", "https://revanced.app")
DONATE_LINK,
}; };
private static final String SOCIAL_LINKS_PROVIDER = "https://api.revanced.app/v2"; private static final String SOCIAL_LINKS_PROVIDER = "https://api.revanced.app/v4";
private static final Route.CompiledRoute GET_SOCIAL = new Route(GET, "/socials").compile(); private static final Route.CompiledRoute GET_SOCIAL = new Route(GET, "/about").compile();
@Nullable @Nullable
private static volatile WebLink[] fetchedLinks; private static volatile WebLink[] fetchedLinks;
@@ -278,7 +303,7 @@ class SocialLinksRoutes {
return fetchedLinks != null; return fetchedLinks != null;
} }
static WebLink[] fetchSocialLinks() { static WebLink[] fetchAboutLinks() {
try { try {
if (hasFetchedLinks()) return fetchedLinks; if (hasFetchedLinks()) return fetchedLinks;
@@ -298,11 +323,22 @@ class SocialLinksRoutes {
} }
JSONObject json = Requester.parseJSONObjectAndDisconnect(connection); JSONObject json = Requester.parseJSONObjectAndDisconnect(connection);
JSONArray socials = json.getJSONArray("socials"); aboutLogoUrl = json.getJSONObject("branding").getString("logo");
List<WebLink> links = new ArrayList<>(); List<WebLink> links = new ArrayList<>();
links.add(DONATE_LINK); // Show donate link first. JSONArray donations = json.getJSONObject("donations").getJSONArray("links");
for (int i = 0, length = donations.length(); i < length; i++) {
WebLink link = new WebLink(donations.getJSONObject(i));
if (link.preferred) {
// This could be localized, but TikTok does not support localized resources.
// All link names returned by the api are also non localized.
link.name = "Donate";
links.add(link);
}
}
JSONArray socials = json.getJSONArray("socials");
for (int i = 0, length = socials.length(); i < length; i++) { for (int i = 0, length = socials.length(); i < length; i++) {
WebLink link = new WebLink(socials.getJSONObject(i)); WebLink link = new WebLink(socials.getJSONObject(i));
links.add(link); links.add(link);

View File

@@ -0,0 +1,56 @@
package app.revanced.extension.tiktok.settings.preference;
import android.content.Context;
import android.util.AttributeSet;
import java.util.Map;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.preference.ReVancedAboutPreference;
@SuppressWarnings("unused")
public class ReVancedTikTokAboutPreference extends ReVancedAboutPreference {
/**
* Because resources cannot be added to TikTok,
* these strings are copied from the shared strings.xml file.
*
* Changes here must also be made in strings.xml
*/
private final Map<String, String> aboutStrings = Map.of(
"revanced_settings_about_links_body", "You are using ReVanced Patches version <i>%s</i>",
"revanced_settings_about_links_dev_header", "Note",
"revanced_settings_about_links_dev_body", "This version is a pre-release and you may experience unexpected issues",
"revanced_settings_about_links_header", "Official links"
);
{
//noinspection deprecation
setTitle("About");
}
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ReVancedTikTokAboutPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ReVancedTikTokAboutPreference(Context context) {
super(context);
}
@Override
protected String getString(String key, Object ... args) {
String format = aboutStrings.get(key);
if (format == null) {
Logger.printException(() -> "Unknown key: " + key);
return "";
}
return String.format(format, args);
}
}

View File

@@ -4,13 +4,14 @@ import android.content.Context;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.tiktok.settings.preference.ReVancedTikTokAboutPreference;
import app.revanced.extension.tiktok.settings.preference.TogglePreference; import app.revanced.extension.tiktok.settings.preference.TogglePreference;
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory { public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
public ExtensionPreferenceCategory(Context context, PreferenceScreen screen) { public ExtensionPreferenceCategory(Context context, PreferenceScreen screen) {
super(context, screen); super(context, screen);
setTitle("Extension"); setTitle("Miscellaneous");
} }
@Override @Override
@@ -20,6 +21,8 @@ public class ExtensionPreferenceCategory extends ConditionalPreferenceCategory {
@Override @Override
public void addPreferences(Context context) { public void addPreferences(Context context) {
addPreference(new ReVancedTikTokAboutPreference(context));
addPreference(new TogglePreference(context, addPreference(new TogglePreference(context,
"Enable debug log", "Enable debug log",
"Show extension debug log.", "Show extension debug log.",

View File

@@ -11,9 +11,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
public class ShowOnLockscreenPatch { public class ShowOnLockscreenPatch {
/**
* @noinspection deprecation
*/
public static Window getWindow(AppCompatActivity activity, float brightness) { public static Window getWindow(AppCompatActivity activity, float brightness) {
Window window = activity.getWindow(); Window window = activity.getWindow();

View File

@@ -82,4 +82,12 @@ public class ThemeHelper {
} }
return Utils.getResourceColor(colorString); return Utils.getResourceColor(colorString);
} }
public static int getBackgroundColor() {
return isDarkTheme() ? getDarkThemeColor() : getLightThemeColor();
}
public static int getForegroundColor() {
return isDarkTheme() ? getLightThemeColor() : getDarkThemeColor();
}
} }

View File

@@ -53,4 +53,18 @@ public final class EnableDebuggingPatch {
return value; return value;
} }
/**
* Injection point.
*/
public static String isStringFeatureFlagEnabled(String value, long flag, String defaultValue) {
if (BaseSettings.DEBUG.get() && !defaultValue.equals(value)) {
if (featureFlags.putIfAbsent(flag, true) == null) {
Logger.printDebug(() -> " string feature is enabled: " + flag
+ " value: " + value + (defaultValue.isEmpty() ? "" : " default: " + defaultValue));
}
}
return value;
}
} }

View File

@@ -24,9 +24,20 @@ public final class MiniplayerPatch {
* Mini player type. Null fields indicates to use the original un-patched value. * Mini player type. Null fields indicates to use the original un-patched value.
*/ */
public enum MiniplayerType { public enum MiniplayerType {
/**
* Disabled. When swiped down the miniplayer is immediately closed.
* Only available with 19.43+
*/
DISABLED(false, null),
/** Unmodified type, and same as un-patched. */ /** Unmodified type, and same as un-patched. */
ORIGINAL(null, null), ORIGINAL(null, null),
/**
* Exactly the same as MINIMAL, and only here for migration of user settings.
* Eventually this should be deleted.
*/
@Deprecated
PHONE(false, null), PHONE(false, null),
MINIMAL(false, null),
TABLET(true, null), TABLET(true, null),
MODERN_1(null, 1), MODERN_1(null, 1),
MODERN_2(null, 2), MODERN_2(null, 2),
@@ -164,6 +175,18 @@ public final class MiniplayerPatch {
OPACITY_LEVEL = (opacity * 255) / 100; OPACITY_LEVEL = (opacity * 255) / 100;
} }
/**
* Injection point.
*
* Enables a handler that immediately closes the miniplayer when the video is minimized,
* effectively disabling the miniplayer.
*/
public static boolean getMiniplayerOnCloseHandler(boolean original) {
return CURRENT_TYPE == ORIGINAL
? original
: CURRENT_TYPE == DISABLED;
}
/** /**
* Injection point. * Injection point.
*/ */

View File

@@ -8,6 +8,7 @@ import app.revanced.extension.shared.Logger;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class PlayerControlsPatch { public class PlayerControlsPatch {
/** /**
* Injection point. * Injection point.
*/ */
@@ -41,4 +42,11 @@ public class PlayerControlsPatch {
public static void fullscreenButtonVisibilityChanged(boolean isVisible) { public static void fullscreenButtonVisibilityChanged(boolean isVisible) {
// Code added during patching. // Code added during patching.
} }
/**
* Injection point.
*/
public static String getPlayerTopControlsLayoutResourceName(String original) {
return "default";
}
} }

View File

@@ -1,14 +1,14 @@
package app.revanced.extension.youtube.patches; package app.revanced.extension.youtube.patches;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import app.revanced.extension.youtube.patches.playback.speed.RememberPlaybackSpeedPatch;
import app.revanced.extension.youtube.shared.VideoState;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.shared.VideoState;
/** /**
* Hooking class for the current playing video. * Hooking class for the current playing video.
* @noinspection unused * @noinspection unused
@@ -120,6 +120,16 @@ public final class VideoInformation {
} }
} }
/**
* Injection point.
*/
public static void videoSpeedChanged(float currentVideoSpeed) {
if (playbackSpeed != currentVideoSpeed) {
Logger.printDebug(() -> "Video speed changed: " + currentVideoSpeed);
playbackSpeed = currentVideoSpeed;
}
}
/** /**
* Injection point. * Injection point.
* Called when user selects a playback speed. * Called when user selects a playback speed.
@@ -131,18 +141,6 @@ public final class VideoInformation {
playbackSpeed = userSelectedPlaybackSpeed; playbackSpeed = userSelectedPlaybackSpeed;
} }
/**
* Overrides the current playback speed.
* <p>
* <b> Used exclusively by {@link RememberPlaybackSpeedPatch} </b>
*/
public static void overridePlaybackSpeed(float speedOverride) {
if (playbackSpeed != speedOverride) {
Logger.printDebug(() -> "Overriding playback speed to: " + speedOverride);
playbackSpeed = speedOverride;
}
}
/** /**
* Injection point. * Injection point.
* *

View File

@@ -31,7 +31,7 @@ public final class LayoutComponentsFilter extends Filter {
"cell_description_body" "cell_description_body"
); );
private static final ByteArrayFilterGroup mixPlaylists = new ByteArrayFilterGroup( private static final ByteArrayFilterGroup mixPlaylists = new ByteArrayFilterGroup(
Settings.HIDE_MIX_PLAYLISTS, null,
"&list=" "&list="
); );
@@ -344,6 +344,10 @@ public final class LayoutComponentsFilter extends Filter {
*/ */
public static boolean filterMixPlaylists(final Object conversionContext, @Nullable final byte[] bytes) { public static boolean filterMixPlaylists(final Object conversionContext, @Nullable final byte[] bytes) {
try { try {
if (!Settings.HIDE_MIX_PLAYLISTS.get()) {
return false;
}
if (bytes == null) { if (bytes == null) {
Logger.printDebug(() -> "bytes is null"); Logger.printDebug(() -> "bytes is null");
return false; return false;

View File

@@ -22,12 +22,12 @@ import app.revanced.extension.youtube.shared.PlayerType;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public final class ShortsFilter extends Filter { public final class ShortsFilter extends Filter {
private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get(); private static final boolean HIDE_SHORTS_NAVIGATION_BAR = Settings.HIDE_SHORTS_NAVIGATION_BAR.get();
private final static String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.eml"; private static final String REEL_CHANNEL_BAR_PATH = "reel_channel_bar.eml";
/** /**
* For paid promotion label and subscribe button that appears in the channel bar. * For paid promotion label and subscribe button that appears in the channel bar.
*/ */
private final static String REEL_METAPANEL_PATH = "reel_metapanel.eml"; private static final String REEL_METAPANEL_PATH = "reel_metapanel.eml";
/** /**
* Tags that appears when opening the Shorts player. * Tags that appears when opening the Shorts player.
@@ -52,7 +52,7 @@ public final class ShortsFilter extends Filter {
private final StringFilterGroup suggestedAction; private final StringFilterGroup suggestedAction;
private final ByteArrayFilterGroupList suggestedActionsGroupList = new ByteArrayFilterGroupList(); private final ByteArrayFilterGroupList suggestedActionsGroupList = new ByteArrayFilterGroupList();
private final StringFilterGroup actionBar; private final StringFilterGroup actionButton;
private final ByteArrayFilterGroupList videoActionButtonGroupList = new ByteArrayFilterGroupList(); private final ByteArrayFilterGroupList videoActionButtonGroupList = new ByteArrayFilterGroupList();
public ShortsFilter() { public ShortsFilter() {
@@ -156,9 +156,9 @@ public final class ShortsFilter extends Filter {
"reel_player_disclosure.eml" "reel_player_disclosure.eml"
); );
actionBar = new StringFilterGroup( actionButton = new StringFilterGroup(
null, null,
"shorts_action_bar" "shorts_video_action_button.eml"
); );
suggestedAction = new StringFilterGroup( suggestedAction = new StringFilterGroup(
@@ -167,7 +167,7 @@ public final class ShortsFilter extends Filter {
); );
addPathCallbacks( addPathCallbacks(
shortsCompactFeedVideoPath, suggestedAction, actionBar, joinButton, subscribeButton, shortsCompactFeedVideoPath, suggestedAction, actionButton, joinButton, subscribeButton,
paidPromotionButton, pausedOverlayButtons, channelBar, fullVideoLinkLabel, videoTitle, paidPromotionButton, pausedOverlayButtons, channelBar, fullVideoLinkLabel, videoTitle,
reelSoundMetadata, soundButton, infoPanel, stickers, likeFountain reelSoundMetadata, soundButton, infoPanel, stickers, likeFountain
); );
@@ -287,7 +287,7 @@ public final class ShortsFilter extends Filter {
} }
// Video action buttons (like, dislike, comment, share, remix) have the same path. // Video action buttons (like, dislike, comment, share, remix) have the same path.
if (matchedGroup == actionBar) { if (matchedGroup == actionButton) {
if (videoActionButtonGroupList.check(protobufBufferArray).isFiltered()) { if (videoActionButtonGroupList.check(protobufBufferArray).isFiltered()) {
return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex);
} }

View File

@@ -1,5 +1,6 @@
package app.revanced.extension.youtube.patches.playback.speed; package app.revanced.extension.youtube.patches.playback.speed;
import static app.revanced.extension.shared.StringRef.sf;
import static app.revanced.extension.shared.StringRef.str; import static app.revanced.extension.shared.StringRef.str;
import android.preference.ListPreference; import android.preference.ListPreference;
@@ -10,15 +11,18 @@ import android.view.ViewParent;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import app.revanced.extension.youtube.patches.components.PlaybackSpeedMenuFilterPatch; import java.util.Arrays;
import app.revanced.extension.youtube.settings.Settings;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
import app.revanced.extension.youtube.patches.components.PlaybackSpeedMenuFilterPatch;
import java.util.Arrays; import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class CustomPlaybackSpeedPatch { public class CustomPlaybackSpeedPatch {
private static final float PLAYBACK_SPEED_AUTO = Settings.PLAYBACK_SPEED_DEFAULT.defaultValue;
/** /**
* Maximum playback speed, exclusive value. Custom speeds must be less than this value. * Maximum playback speed, exclusive value. Custom speeds must be less than this value.
* *
@@ -26,7 +30,7 @@ public class CustomPlaybackSpeedPatch {
* and the UI selector starts flickering and acting weird. * and the UI selector starts flickering and acting weird.
* Over 10x and the speeds show up out of order in the UI selector. * Over 10x and the speeds show up out of order in the UI selector.
*/ */
public static final float MAXIMUM_PLAYBACK_SPEED = 8; public static final float PLAYBACK_SPEED_MAXIMUM = 8;
/** /**
* Custom playback speeds. * Custom playback speeds.
@@ -69,8 +73,8 @@ public class CustomPlaybackSpeedPatch {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
if (speedFloat >= MAXIMUM_PLAYBACK_SPEED) { if (speedFloat >= PLAYBACK_SPEED_MAXIMUM) {
resetCustomSpeeds(str("revanced_custom_playback_speeds_invalid", MAXIMUM_PLAYBACK_SPEED)); resetCustomSpeeds(str("revanced_custom_playback_speeds_invalid", PLAYBACK_SPEED_MAXIMUM));
loadCustomSpeeds(); loadCustomSpeeds();
return; return;
} }
@@ -98,10 +102,15 @@ public class CustomPlaybackSpeedPatch {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public static void initializeListPreference(ListPreference preference) { public static void initializeListPreference(ListPreference preference) {
if (preferenceListEntries == null) { if (preferenceListEntries == null) {
preferenceListEntries = new String[customPlaybackSpeeds.length]; final int numberOfEntries = customPlaybackSpeeds.length + 1;
preferenceListEntryValues = new String[customPlaybackSpeeds.length]; preferenceListEntries = new String[numberOfEntries];
preferenceListEntryValues = new String[numberOfEntries];
int i = 0; // Auto speed (same behavior as unpatched).
preferenceListEntries[0] = sf("revanced_custom_playback_speeds_auto").toString();
preferenceListEntryValues[0] = String.valueOf(PLAYBACK_SPEED_AUTO);
int i = 1;
for (float speed : customPlaybackSpeeds) { for (float speed : customPlaybackSpeeds) {
String speedString = String.valueOf(speed); String speedString = String.valueOf(speed);
preferenceListEntries[i] = speedString + "x"; preferenceListEntries[i] = speedString + "x";

View File

@@ -12,6 +12,8 @@ public final class RememberPlaybackSpeedPatch {
private static final long TOAST_DELAY_MILLISECONDS = 750; private static final long TOAST_DELAY_MILLISECONDS = 750;
private static volatile boolean newVideoStarted;
private static long lastTimeSpeedChanged; private static long lastTimeSpeedChanged;
/** /**
@@ -19,7 +21,7 @@ public final class RememberPlaybackSpeedPatch {
*/ */
public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) { public static void newVideoStarted(VideoInformation.PlaybackController ignoredPlayerController) {
Logger.printDebug(() -> "newVideoStarted"); Logger.printDebug(() -> "newVideoStarted");
VideoInformation.overridePlaybackSpeed(Settings.PLAYBACK_SPEED_DEFAULT.get()); newVideoStarted = true;
} }
/** /**
@@ -29,42 +31,56 @@ public final class RememberPlaybackSpeedPatch {
* @param playbackSpeed The playback speed the user selected * @param playbackSpeed The playback speed the user selected
*/ */
public static void userSelectedPlaybackSpeed(float playbackSpeed) { public static void userSelectedPlaybackSpeed(float playbackSpeed) {
if (Settings.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED.get()) { try {
// With the 0.05x menu, if the speed is set by integrations to higher than 2.0x if (Settings.REMEMBER_PLAYBACK_SPEED_LAST_SELECTED.get()) {
// then the menu will allow increasing without bounds but the max speed is // With the 0.05x menu, if the speed is set by integrations to higher than 2.0x
// still capped to under 8.0x. // then the menu will allow increasing without bounds but the max speed is
playbackSpeed = Math.min(playbackSpeed, CustomPlaybackSpeedPatch.MAXIMUM_PLAYBACK_SPEED - 0.05f); // still capped to under 8.0x.
playbackSpeed = Math.min(playbackSpeed, CustomPlaybackSpeedPatch.PLAYBACK_SPEED_MAXIMUM - 0.05f);
// Prevent toast spamming if using the 0.05x adjustments. // Prevent toast spamming if using the 0.05x adjustments.
// Show exactly one toast after the user stops interacting with the speed menu. // Show exactly one toast after the user stops interacting with the speed menu.
final long now = System.currentTimeMillis(); final long now = System.currentTimeMillis();
lastTimeSpeedChanged = now; lastTimeSpeedChanged = now;
final float finalPlaybackSpeed = playbackSpeed; final float finalPlaybackSpeed = playbackSpeed;
Utils.runOnMainThreadDelayed(() -> { Utils.runOnMainThreadDelayed(() -> {
if (lastTimeSpeedChanged != now) { if (lastTimeSpeedChanged != now) {
// The user made additional speed adjustments and this call is outdated. // The user made additional speed adjustments and this call is outdated.
return; return;
} }
if (Settings.PLAYBACK_SPEED_DEFAULT.get() == finalPlaybackSpeed) { if (Settings.PLAYBACK_SPEED_DEFAULT.get() == finalPlaybackSpeed) {
// User changed to a different speed and immediately changed back. // User changed to a different speed and immediately changed back.
// Or the user is going past 8.0x in the glitched out 0.05x menu. // Or the user is going past 8.0x in the glitched out 0.05x menu.
return; return;
} }
Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed); Settings.PLAYBACK_SPEED_DEFAULT.save(finalPlaybackSpeed);
Utils.showToastLong(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x"))); Utils.showToastLong(str("revanced_remember_playback_speed_toast", (finalPlaybackSpeed + "x")));
}, TOAST_DELAY_MILLISECONDS); }, TOAST_DELAY_MILLISECONDS);
}
} catch (Exception ex) {
Logger.printException(() -> "userSelectedPlaybackSpeed failure", ex);
} }
} }
/** /**
* Injection point. * Injection point.
* Overrides the video speed. Called after video loads, and immediately after user selects a different playback speed * Overrides the video speed. Called after video loads,
* and immediately after the user selects a different playback speed.
*/ */
public static float getPlaybackSpeedOverride() { public static float getPlaybackSpeedOverride() {
return VideoInformation.getPlaybackSpeed(); if (newVideoStarted) {
newVideoStarted = false;
final float defaultSpeed = Settings.PLAYBACK_SPEED_DEFAULT.get();
if (defaultSpeed > 0) {
return defaultSpeed;
}
}
return -2.0f;
} }
} }

View File

@@ -8,6 +8,17 @@ import android.os.Build;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
public enum ClientType { public enum ClientType {
// Specific purpose for age restricted, or private videos, because the iOS client is not logged in.
ANDROID_VR(28,
"Quest 3",
"12",
"com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip",
"32", // Android 12.1
"1.56.21",
"ANDROID_VR",
true
),
// Specific for kids videos.
// https://dumps.tadiphone.dev/dumps/oculus/eureka // https://dumps.tadiphone.dev/dumps/oculus/eureka
IOS(5, IOS(5,
// iPhone 15 supports AV1 hardware decoding. // iPhone 15 supports AV1 hardware decoding.
@@ -25,14 +36,9 @@ public enum ClientType {
null, null,
// Version number should be a valid iOS release. // Version number should be a valid iOS release.
// https://www.ipa4fun.com/history/185230 // https://www.ipa4fun.com/history/185230
"19.10.7" "19.10.7",
), "IOS",
ANDROID_VR(28, false
"Quest 3",
"12",
"com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip",
"32", // Android 12.1
"1.56.21"
); );
/** /**
@@ -44,7 +50,7 @@ public enum ClientType {
/** /**
* Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model) * Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model)
*/ */
public final String model; public final String deviceModel;
/** /**
* Device OS version. * Device OS version.
@@ -63,17 +69,37 @@ public enum ClientType {
@Nullable @Nullable
public final String androidSdkVersion; public final String androidSdkVersion;
/**
* Client name.
*/
public final String clientName;
/** /**
* App version. * App version.
*/ */
public final String appVersion; public final String clientVersion;
ClientType(int id, String model, String osVersion, String userAgent, @Nullable String androidSdkVersion, String appVersion) { /**
* If the client can access the API logged in.
*/
public final boolean canLogin;
ClientType(int id,
String deviceModel,
String osVersion,
String userAgent,
@Nullable String androidSdkVersion,
String clientVersion,
String clientName,
boolean canLogin
) {
this.id = id; this.id = id;
this.model = model; this.deviceModel = deviceModel;
this.osVersion = osVersion; this.osVersion = osVersion;
this.userAgent = userAgent; this.userAgent = userAgent;
this.androidSdkVersion = androidSdkVersion; this.androidSdkVersion = androidSdkVersion;
this.appVersion = appVersion; this.clientVersion = clientVersion;
this.clientName = clientName;
this.canLogin = canLogin;
} }
} }

View File

@@ -12,15 +12,13 @@ import app.revanced.extension.youtube.requests.Requester;
import app.revanced.extension.youtube.requests.Route; import app.revanced.extension.youtube.requests.Route;
final class PlayerRoutes { final class PlayerRoutes {
private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/";
static final Route.CompiledRoute GET_STREAMING_DATA = new Route( static final Route.CompiledRoute GET_STREAMING_DATA = new Route(
Route.Method.POST, Route.Method.POST,
"player" + "player" +
"?fields=streamingData" + "?fields=streamingData" +
"&alt=proto" "&alt=proto"
).compile(); ).compile();
private static final String YT_API_URL = "https://youtubei.googleapis.com/youtubei/v1/";
/** /**
* TCP connection and HTTP read timeout * TCP connection and HTTP read timeout
*/ */
@@ -30,15 +28,15 @@ final class PlayerRoutes {
} }
static String createInnertubeBody(ClientType clientType) { static String createInnertubeBody(ClientType clientType) {
JSONObject innerTubeBody = new JSONObject(); JSONObject innerTubeBody = new JSONObject();
try { try {
JSONObject context = new JSONObject(); JSONObject context = new JSONObject();
JSONObject client = new JSONObject(); JSONObject client = new JSONObject();
client.put("clientName", clientType.name()); client.put("clientName", clientType.name());
client.put("clientVersion", clientType.appVersion); client.put("clientVersion", clientType.clientVersion);
client.put("deviceModel", clientType.model); client.put("deviceModel", clientType.deviceModel);
client.put("osVersion", clientType.osVersion); client.put("osVersion", clientType.osVersion);
if (clientType.androidSdkVersion != null) { if (clientType.androidSdkVersion != null) {
client.put("androidSdkVersion", clientType.androidSdkVersion); client.put("androidSdkVersion", clientType.androidSdkVersion);
@@ -57,7 +55,9 @@ final class PlayerRoutes {
return innerTubeBody.toString(); return innerTubeBody.toString();
} }
/** @noinspection SameParameterValue*/ /**
* @noinspection SameParameterValue
*/
static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route, ClientType clientType) throws IOException { static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.CompiledRoute route, ClientType clientType) throws IOException {
var connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route); var connection = Requester.getConnectionFromCompiledRoute(YT_API_URL, route);

View File

@@ -28,7 +28,7 @@ import app.revanced.extension.youtube.settings.Settings;
/** /**
* Video streaming data. Fetching is tied to the behavior YT uses, * Video streaming data. Fetching is tied to the behavior YT uses,
* where this class fetches the streams only when YT fetches. * where this class fetches the streams only when YT fetches.
* * <p>
* Effectively the cache expiration of these fetches is the same as the stock app, * Effectively the cache expiration of these fetches is the same as the stock app,
* since the stock app would not use expired streams and therefor * since the stock app would not use expired streams and therefor
* the extension replace stream hook is called only if YT * the extension replace stream hook is called only if YT
@@ -37,38 +37,20 @@ import app.revanced.extension.youtube.settings.Settings;
public class StreamingDataRequest { public class StreamingDataRequest {
private static final ClientType[] CLIENT_ORDER_TO_USE; private static final ClientType[] CLIENT_ORDER_TO_USE;
private static final String AUTHORIZATION_HEADER = "Authorization";
static {
ClientType[] allClientTypes = ClientType.values();
ClientType preferredClient = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
CLIENT_ORDER_TO_USE[0] = preferredClient;
int i = 1;
for (ClientType c : allClientTypes) {
if (c != preferredClient) {
CLIENT_ORDER_TO_USE[i++] = c;
}
}
}
private static final String[] REQUEST_HEADER_KEYS = { private static final String[] REQUEST_HEADER_KEYS = {
"Authorization", // Available only to logged in users. AUTHORIZATION_HEADER, // Available only to logged-in users.
"X-GOOG-API-FORMAT-VERSION", "X-GOOG-API-FORMAT-VERSION",
"X-Goog-Visitor-Id" "X-Goog-Visitor-Id"
}; };
/** /**
* TCP connection and HTTP read timeout. * TCP connection and HTTP read timeout.
*/ */
private static final int HTTP_TIMEOUT_MILLISECONDS = 10 * 1000; private static final int HTTP_TIMEOUT_MILLISECONDS = 10 * 1000;
/** /**
* Any arbitrarily large value, but must be at least twice {@link #HTTP_TIMEOUT_MILLISECONDS} * Any arbitrarily large value, but must be at least twice {@link #HTTP_TIMEOUT_MILLISECONDS}
*/ */
private static final int MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000; private static final int MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000;
private static final Map<String, StreamingDataRequest> cache = Collections.synchronizedMap( private static final Map<String, StreamingDataRequest> cache = Collections.synchronizedMap(
new LinkedHashMap<>(100) { new LinkedHashMap<>(100) {
/** /**
@@ -86,8 +68,32 @@ public class StreamingDataRequest {
} }
}); });
static {
ClientType[] allClientTypes = ClientType.values();
ClientType preferredClient = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
CLIENT_ORDER_TO_USE = new ClientType[allClientTypes.length];
CLIENT_ORDER_TO_USE[0] = preferredClient;
int i = 1;
for (ClientType c : allClientTypes) {
if (c != preferredClient) {
CLIENT_ORDER_TO_USE[i++] = c;
}
}
}
private final String videoId;
private final Future<ByteBuffer> future;
private StreamingDataRequest(String videoId, Map<String, String> playerHeaders) {
Objects.requireNonNull(playerHeaders);
this.videoId = videoId;
this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders));
}
public static void fetchRequest(String videoId, Map<String, String> fetchHeaders) { public static void fetchRequest(String videoId, Map<String, String> fetchHeaders) {
// Always fetch, even if there is a existing request for the same video. // Always fetch, even if there is an existing request for the same video.
cache.put(videoId, new StreamingDataRequest(videoId, fetchHeaders)); cache.put(videoId, new StreamingDataRequest(videoId, fetchHeaders));
} }
@@ -119,6 +125,10 @@ public class StreamingDataRequest {
connection.setReadTimeout(HTTP_TIMEOUT_MILLISECONDS); connection.setReadTimeout(HTTP_TIMEOUT_MILLISECONDS);
for (String key : REQUEST_HEADER_KEYS) { for (String key : REQUEST_HEADER_KEYS) {
if (!clientType.canLogin && key.equals(AUTHORIZATION_HEADER)) {
continue;
}
String value = playerHeaders.get(key); String value = playerHeaders.get(key);
if (value != null) { if (value != null) {
connection.setRequestProperty(key, value); connection.setRequestProperty(key, value);
@@ -186,15 +196,6 @@ public class StreamingDataRequest {
return null; return null;
} }
private final String videoId;
private final Future<ByteBuffer> future;
private StreamingDataRequest(String videoId, Map<String, String> playerHeaders) {
Objects.requireNonNull(playerHeaders);
this.videoId = videoId;
this.future = Utils.submitOnBackgroundThread(() -> fetch(videoId, playerHeaders));
}
public boolean fetchCompleted() { public boolean fetchCompleted() {
return future.isDone(); return future.isDone();
} }

View File

@@ -2,9 +2,12 @@ package app.revanced.extension.youtube.patches.theme;
import static app.revanced.extension.shared.StringRef.str; import static app.revanced.extension.shared.StringRef.str;
import android.content.res.Resources;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.drawable.AnimatedVectorDrawable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Locale;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.Utils;
@@ -16,7 +19,8 @@ public final class SeekbarColorPatch {
private static final boolean SEEKBAR_CUSTOM_COLOR_ENABLED = Settings.SEEKBAR_CUSTOM_COLOR.get(); private static final boolean SEEKBAR_CUSTOM_COLOR_ENABLED = Settings.SEEKBAR_CUSTOM_COLOR.get();
/** /**
* Default color of the seekbar. * Default color of the litho seekbar.
* Differs slightly from the default custom seekbar color setting.
*/ */
private static final int ORIGINAL_SEEKBAR_COLOR = 0xFFFF0000; private static final int ORIGINAL_SEEKBAR_COLOR = 0xFFFF0000;
@@ -72,12 +76,76 @@ public final class SeekbarColorPatch {
return seekbarColor; return seekbarColor;
} }
/**
* Injection point
*/
public static boolean playerSeekbarGradientEnabled(boolean original) { public static boolean playerSeekbarGradientEnabled(boolean original) {
if (SEEKBAR_CUSTOM_COLOR_ENABLED) return false; if (SEEKBAR_CUSTOM_COLOR_ENABLED) return false;
return original; return original;
} }
/**
* Injection point
*/
public static boolean useLotteLaunchSplashScreen(boolean original) {
Logger.printDebug(() -> "useLotteLaunchSplashScreen original: " + original);
if (SEEKBAR_CUSTOM_COLOR_ENABLED) return false;
return original;
}
private static int colorChannelTo3Bits(int channel8Bits) {
final float channel3Bits = channel8Bits * 7 / 255f;
// If a color channel is near zero, then allow rounding up so values between
// 0x12 and 0x23 will show as 0x24. But always round down when the channel is
// near full saturation, otherwise rounding to nearest will cause all values
// between 0xEC and 0xFE to always show as full saturation (0xFF).
return channel3Bits < 6
? Math.round(channel3Bits)
: (int) channel3Bits;
}
private static String get9BitStyleIdentifier(int color24Bit) {
final int r3 = colorChannelTo3Bits(Color.red(color24Bit));
final int g3 = colorChannelTo3Bits(Color.green(color24Bit));
final int b3 = colorChannelTo3Bits(Color.blue(color24Bit));
return String.format(Locale.US, "splash_seekbar_color_style_%d_%d_%d", r3, g3, b3);
}
/**
* Injection point
*/
public static void setSplashAnimationDrawableTheme(AnimatedVectorDrawable vectorDrawable) {
// Alternatively a ColorMatrixColorFilter can be used to change the color of the drawable
// without using any styles, but a color filter cannot selectively change the seekbar
// while keeping the red YT logo untouched.
// Even if the seekbar color xml value is changed to a completely different color (such as green),
// a color filter still cannot be selectively applied when the drawable has more than 1 color.
try {
String seekbarStyle = get9BitStyleIdentifier(seekbarColor);
Logger.printDebug(() -> "Using splash seekbar style: " + seekbarStyle);
final int styleIdentifierDefault = Utils.getResourceIdentifier(
seekbarStyle,
"style"
);
if (styleIdentifierDefault == 0) {
throw new RuntimeException("Seekbar style not found: " + seekbarStyle);
}
Resources.Theme theme = Utils.getContext().getResources().newTheme();
theme.applyStyle(styleIdentifierDefault, true);
vectorDrawable.applyTheme(theme);
} catch (Exception ex) {
Logger.printException(() -> "setSplashAnimationDrawableTheme failure", ex);
}
}
/** /**
* Injection point. * Injection point.
* *
@@ -189,4 +257,4 @@ public final class SeekbarColorPatch {
private static float clamp(float value, float lower, float upper) { private static float clamp(float value, float lower, float upper) {
return Math.max(lower, Math.min(value, upper)); return Math.max(lower, Math.min(value, upper));
} }
} }

View File

@@ -147,6 +147,7 @@ public class ReturnYouTubeDislikeApi {
*/ */
private static void randomlyWaitIfLocallyDebugging() { private static void randomlyWaitIfLocallyDebugging() {
final boolean DEBUG_RANDOMLY_DELAY_NETWORK_CALLS = false; // set true to debug UI final boolean DEBUG_RANDOMLY_DELAY_NETWORK_CALLS = false; // set true to debug UI
//noinspection ConstantValue
if (DEBUG_RANDOMLY_DELAY_NETWORK_CALLS) { if (DEBUG_RANDOMLY_DELAY_NETWORK_CALLS) {
final long amountOfTimeToWaste = (long) (Math.random() final long amountOfTimeToWaste = (long) (Math.random()
* (API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS + API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS)); * (API_GET_VOTES_TCP_TIMEOUT_MILLISECONDS + API_GET_VOTES_HTTP_TIMEOUT_MILLISECONDS));
@@ -187,6 +188,7 @@ public class ReturnYouTubeDislikeApi {
*/ */
private static boolean checkIfRateLimitWasHit(int httpResponseCode) { private static boolean checkIfRateLimitWasHit(int httpResponseCode) {
final boolean DEBUG_RATE_LIMIT = false; // set to true, to verify rate limit works final boolean DEBUG_RATE_LIMIT = false; // set to true, to verify rate limit works
//noinspection ConstantValue
if (DEBUG_RATE_LIMIT) { if (DEBUG_RATE_LIMIT) {
final double RANDOM_RATE_LIMIT_PERCENTAGE = 0.2; // 20% chance of a triggering a rate limit final double RANDOM_RATE_LIMIT_PERCENTAGE = 0.2; // 20% chance of a triggering a rate limit
if (Math.random() < RANDOM_RATE_LIMIT_PERCENTAGE) { if (Math.random() < RANDOM_RATE_LIMIT_PERCENTAGE) {

View File

@@ -7,6 +7,7 @@ import android.view.ViewGroup;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView; import android.widget.TextView;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment;
import app.revanced.extension.youtube.ThemeHelper; import app.revanced.extension.youtube.ThemeHelper;
import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment; import app.revanced.extension.youtube.settings.preference.ReVancedPreferenceFragment;
import app.revanced.extension.youtube.settings.preference.ReturnYouTubeDislikePreferenceFragment; import app.revanced.extension.youtube.settings.preference.ReturnYouTubeDislikePreferenceFragment;
@@ -39,7 +40,7 @@ public class LicenseActivityHook {
PreferenceFragment fragment; PreferenceFragment fragment;
String toolbarTitleResourceName; String toolbarTitleResourceName;
String dataString = licenseActivity.getIntent().getDataString(); String dataString = Objects.requireNonNull(licenseActivity.getIntent().getDataString());
switch (dataString) { switch (dataString) {
case "revanced_sb_settings_intent": case "revanced_sb_settings_intent":
toolbarTitleResourceName = "revanced_sb_settings_title"; toolbarTitleResourceName = "revanced_sb_settings_title";
@@ -59,12 +60,14 @@ public class LicenseActivityHook {
} }
setToolbarTitle(licenseActivity, toolbarTitleResourceName); setToolbarTitle(licenseActivity, toolbarTitleResourceName);
//noinspection deprecation
licenseActivity.getFragmentManager() licenseActivity.getFragmentManager()
.beginTransaction() .beginTransaction()
.replace(getResourceIdentifier("revanced_settings_fragments", "id"), fragment) .replace(getResourceIdentifier("revanced_settings_fragments", "id"), fragment)
.commit(); .commit();
} catch (Exception ex) { } catch (Exception ex) {
Logger.printException(() -> "onCreate failure", ex); Logger.printException(() -> "initialize failure", ex);
} }
} }
@@ -80,11 +83,7 @@ public class LicenseActivityHook {
ViewGroup toolbar = activity.findViewById(getToolbarResourceId()); ViewGroup toolbar = activity.findViewById(getToolbarResourceId());
ImageButton imageButton = Objects.requireNonNull(getChildView(toolbar, false, ImageButton imageButton = Objects.requireNonNull(getChildView(toolbar, false,
view -> view instanceof ImageButton)); view -> view instanceof ImageButton));
final int backButtonResource = getResourceIdentifier(ThemeHelper.isDarkTheme() imageButton.setImageDrawable(AbstractPreferenceFragment.getBackButtonDrawable());
? "yt_outline_arrow_left_white_24"
: "yt_outline_arrow_left_black_24",
"drawable");
imageButton.setImageDrawable(activity.getResources().getDrawable(backButtonResource));
imageButton.setOnClickListener(view -> activity.onBackPressed()); imageButton.setOnClickListener(view -> activity.onBackPressed());
} }

View File

@@ -9,6 +9,7 @@ import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerH
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType;
import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.*; import static app.revanced.extension.youtube.patches.MiniplayerPatch.MiniplayerType.*;
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability; import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
import static app.revanced.extension.youtube.patches.VersionCheckPatch.IS_19_17_OR_GREATER;
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.*; import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.*;
import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Logger;
@@ -19,11 +20,9 @@ import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.StillIm
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailOption;
import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime; import app.revanced.extension.youtube.patches.AlternativeThumbnailsPatch.ThumbnailStillTime;
import app.revanced.extension.youtube.patches.spoof.ClientType; import app.revanced.extension.youtube.patches.spoof.ClientType;
import app.revanced.extension.youtube.patches.spoof.SpoofAppVersionPatch;
import app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch; import app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings; import app.revanced.extension.youtube.sponsorblock.SponsorBlockSettings;
@SuppressWarnings("deprecation")
public class Settings extends BaseSettings { public class Settings extends BaseSettings {
// Video // Video
public static final BooleanSetting RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE); public static final BooleanSetting RESTORE_OLD_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_restore_old_video_quality_menu", TRUE);
@@ -33,7 +32,7 @@ public class Settings extends BaseSettings {
// Speed // Speed
public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE); public static final BooleanSetting REMEMBER_PLAYBACK_SPEED_LAST_SELECTED = new BooleanSetting("revanced_remember_playback_speed_last_selected", FALSE);
public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE); public static final BooleanSetting CUSTOM_SPEED_MENU = new BooleanSetting("revanced_custom_speed_menu", TRUE);
public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", 1.0f); public static final FloatSetting PLAYBACK_SPEED_DEFAULT = new FloatSetting("revanced_playback_speed_default", -2.0f);
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds", public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
"0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0", true); "0.25\n0.5\n0.75\n0.9\n0.95\n1.0\n1.05\n1.1\n1.25\n1.5\n1.75\n2.0\n3.0\n4.0\n5.0", true);
@@ -128,8 +127,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_AUTOPLAY_BUTTON = new BooleanSetting("revanced_hide_autoplay_button", TRUE, true); public static final BooleanSetting HIDE_AUTOPLAY_BUTTON = new BooleanSetting("revanced_hide_autoplay_button", TRUE, true);
public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_hide_cast_button", TRUE, true); public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_hide_cast_button", TRUE, true);
public static final BooleanSetting HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS = new BooleanSetting("revanced_hide_player_previous_next_buttons", FALSE, true); public static final BooleanSetting HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS = new BooleanSetting("revanced_hide_player_previous_next_buttons", FALSE, true);
@Deprecated private static final BooleanSetting DEPRECATED_HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true);
public static final BooleanSetting HIDE_PLAYER_BUTTONS = new BooleanSetting("revanced_hide_player_buttons", FALSE, true);
public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE); public static final BooleanSetting COPY_VIDEO_URL = new BooleanSetting("revanced_copy_video_url", FALSE);
public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE); public static final BooleanSetting COPY_VIDEO_URL_TIMESTAMP = new BooleanSetting("revanced_copy_video_url_timestamp", TRUE);
public static final BooleanSetting PLAYBACK_SPEED_DIALOG_BUTTON = new BooleanSetting("revanced_playback_speed_dialog_button", FALSE); public static final BooleanSetting PLAYBACK_SPEED_DIALOG_BUTTON = new BooleanSetting("revanced_playback_speed_dialog_button", FALSE);
@@ -192,14 +190,13 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_PLAYER_FLYOUT_SLEEP_TIMER = new BooleanSetting("revanced_hide_player_flyout_sleep_timer", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_SLEEP_TIMER = new BooleanSetting("revanced_hide_player_flyout_sleep_timer", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_STABLE_VOLUME = new BooleanSetting("revanced_hide_player_flyout_stable_volume", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_STABLE_VOLUME = new BooleanSetting("revanced_hide_player_flyout_stable_volume", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_WATCH_IN_VR = new BooleanSetting("revanced_hide_player_flyout_watch_in_vr", TRUE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_WATCH_IN_VR = new BooleanSetting("revanced_hide_player_flyout_watch_in_vr", TRUE);
@Deprecated
private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE); private static final BooleanSetting DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_video_quality_menu_footer", FALSE);
public static final BooleanSetting HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_player_flyout_video_quality_footer", FALSE); public static final BooleanSetting HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER = new BooleanSetting("revanced_hide_player_flyout_video_quality_footer", FALSE);
// General layout // General layout
public static final EnumSetting<StartPage> CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.ORIGINAL, true); public static final EnumSetting<StartPage> CHANGE_START_PAGE = new EnumSetting<>("revanced_change_start_page", StartPage.ORIGINAL, true);
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message"); public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", FALSE, true, "revanced_spoof_app_version_user_dialog_message");
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", "17.41.37", true, parent(SPOOF_APP_VERSION)); public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", IS_19_17_OR_GREATER ? "18.38.44" : "17.33.42", true, parent(SPOOF_APP_VERSION));
public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message"); public static final BooleanSetting TABLET_LAYOUT = new BooleanSetting("revanced_tablet_layout", FALSE, true, "revanced_tablet_layout_user_dialog_message");
public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true); public static final BooleanSetting WIDE_SEARCHBAR = new BooleanSetting("revanced_wide_searchbar", FALSE, true);
public static final BooleanSetting BYPASS_IMAGE_REGION_RESTRICTIONS = new BooleanSetting("revanced_bypass_image_region_restrictions", FALSE, true); public static final BooleanSetting BYPASS_IMAGE_REGION_RESTRICTIONS = new BooleanSetting("revanced_bypass_image_region_restrictions", FALSE, true);
@@ -235,7 +232,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_SHORTS_UPCOMING_BUTTON = new BooleanSetting("revanced_hide_shorts_upcoming_button", TRUE); public static final BooleanSetting HIDE_SHORTS_UPCOMING_BUTTON = new BooleanSetting("revanced_hide_shorts_upcoming_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_GREEN_SCREEN_BUTTON = new BooleanSetting("revanced_hide_shorts_green_screen_button", TRUE); public static final BooleanSetting HIDE_SHORTS_GREEN_SCREEN_BUTTON = new BooleanSetting("revanced_hide_shorts_green_screen_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_HASHTAG_BUTTON = new BooleanSetting("revanced_hide_shorts_hashtag_button", TRUE); public static final BooleanSetting HIDE_SHORTS_HASHTAG_BUTTON = new BooleanSetting("revanced_hide_shorts_hashtag_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_SEARCH_SUGGESTIONS = new BooleanSetting("revanced_hide_shorts_search_suggestions", FALSE); public static final BooleanSetting HIDE_SHORTS_SEARCH_SUGGESTIONS = new BooleanSetting("revanced_hide_shorts_search_suggestions", TRUE);
public static final BooleanSetting HIDE_SHORTS_STICKERS = new BooleanSetting("revanced_hide_shorts_stickers", TRUE); public static final BooleanSetting HIDE_SHORTS_STICKERS = new BooleanSetting("revanced_hide_shorts_stickers", TRUE);
public static final BooleanSetting HIDE_SHORTS_SUPER_THANKS_BUTTON = new BooleanSetting("revanced_hide_shorts_super_thanks_button", TRUE); public static final BooleanSetting HIDE_SHORTS_SUPER_THANKS_BUTTON = new BooleanSetting("revanced_hide_shorts_super_thanks_button", TRUE);
public static final BooleanSetting HIDE_SHORTS_LIKE_FOUNTAIN = new BooleanSetting("revanced_hide_shorts_like_fountain", TRUE); public static final BooleanSetting HIDE_SHORTS_LIKE_FOUNTAIN = new BooleanSetting("revanced_hide_shorts_like_fountain", TRUE);
@@ -274,7 +271,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true, public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
"revanced_spoof_device_dimensions_user_dialog_message"); "revanced_spoof_device_dimensions_user_dialog_message");
public static final BooleanSetting BYPASS_URL_REDIRECTS = new BooleanSetting("revanced_bypass_url_redirects", TRUE); public static final BooleanSetting BYPASS_URL_REDIRECTS = new BooleanSetting("revanced_bypass_url_redirects", TRUE);
public static final BooleanSetting ANNOUNCEMENTS = new BooleanSetting("revanced_announcements", TRUE); public static final BooleanSetting ANNOUNCEMENTS = new BooleanSetting("revanced_announcements", TRUE, false, false);
public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true,"revanced_spoof_video_streams_user_dialog_message"); public static final BooleanSetting SPOOF_VIDEO_STREAMS = new BooleanSetting("revanced_spoof_video_streams", TRUE, true,"revanced_spoof_video_streams_user_dialog_message");
public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true, public static final BooleanSetting SPOOF_VIDEO_STREAMS_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_video_streams_ios_force_avc", FALSE, true,
"revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofVideoStreamsPatch.ForceiOSAVCAvailability()); "revanced_spoof_video_streams_ios_force_avc_user_dialog_message", new SpoofVideoStreamsPatch.ForceiOSAVCAvailability());
@@ -377,16 +374,21 @@ public class Settings extends BaseSettings {
migrateOldSettingToNew(DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING, SB_PRIVATE_USER_ID); migrateOldSettingToNew(DEPRECATED_SB_UUID_OLD_MIGRATION_SETTING, SB_PRIVATE_USER_ID);
// Old spoof versions that no longer work reliably. migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS);
if (SpoofAppVersionPatch.isSpoofingToLessThan("17.33.00")) {
Logger.printInfo(() -> "Resetting spoof app version target");
Settings.SPOOF_APP_VERSION_TARGET.resetToDefault();
}
migrateOldSettingToNew(HIDE_PLAYER_BUTTONS, HIDE_PLAYER_PREVIOUS_NEXT_BUTTONS);
migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER); migrateOldSettingToNew(DEPRECATED_HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER, HIDE_PLAYER_FLYOUT_VIDEO_QUALITY_FOOTER);
// Old spoof versions that no longer work reliably.
if (SPOOF_APP_VERSION_TARGET.get().compareTo(SPOOF_APP_VERSION_TARGET.defaultValue) < 0) {
Logger.printInfo(() -> "Resetting spoof app version target");
SPOOF_APP_VERSION_TARGET.resetToDefault();
}
// Migrate renamed enum type.
if (MINIPLAYER_TYPE.get() == PHONE) {
MINIPLAYER_TYPE.save(MINIMAL);
}
// endregion // endregion
} }
} }

View File

@@ -49,7 +49,7 @@ enum class PlayerType {
companion object { companion object {
private val nameToPlayerType = values().associateBy { it.name } private val nameToPlayerType = PlayerType.entries.associateBy { it.name }
@JvmStatic @JvmStatic
fun setFromString(enumName: String) { fun setFromString(enumName: String) {

View File

@@ -22,7 +22,7 @@ enum class VideoState {
companion object { companion object {
private val nameToVideoState = values().associateBy { it.name } private val nameToVideoState = VideoState.entries.associateBy { it.name }
@JvmStatic @JvmStatic
fun setFromString(enumName: String) { fun setFromString(enumName: String) {

View File

@@ -382,7 +382,6 @@ public class SponsorBlockUtils {
return statsNumberFormatter.format(viewCount); return statsNumberFormatter.format(viewCount);
} }
@SuppressWarnings("ConstantConditions")
private static long parseSegmentTime(@NonNull String time) { private static long parseSegmentTime(@NonNull String time) {
Matcher matcher = manualEditTimePattern.matcher(time); Matcher matcher = manualEditTimePattern.matcher(time);
if (!matcher.matches()) { if (!matcher.matches()) {

View File

@@ -113,6 +113,7 @@ public class SBRequester {
// Could benefit from: // Could benefit from:
// 1) collection of YouTube videos with test segment times (verify client skip timing matches the video, verify seekbar draws correctly) // 1) collection of YouTube videos with test segment times (verify client skip timing matches the video, verify seekbar draws correctly)
// 2) unit tests (verify everything else) // 2) unit tests (verify everything else)
//noinspection ConstantValue
if (false) { if (false) {
segments.clear(); segments.clear();
// Test auto-hide skip button: // Test auto-hide skip button:

View File

@@ -1,7 +1,5 @@
package app.revanced.extension.youtube.sponsorblock.ui; package app.revanced.extension.youtube.sponsorblock.ui;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;

View File

@@ -107,12 +107,13 @@ public final class NewSegmentLayout extends FrameLayout {
*/ */
private void initializeButton(final Context context, final String resourceIdentifierName, private void initializeButton(final Context context, final String resourceIdentifierName,
final ButtonOnClickHandlerFunction handler, final String debugMessage) { final ButtonOnClickHandlerFunction handler, final String debugMessage) {
final ImageButton button = findViewById(getResourceIdentifier(context, resourceIdentifierName, "id")); ImageButton button = findViewById(getResourceIdentifier(context, resourceIdentifierName, "id"));
// Add ripple effect
button.setBackgroundResource(rippleEffectId); button.setBackgroundResource(rippleEffectId);
RippleDrawable rippleDrawable = (RippleDrawable) button.getBackground(); RippleDrawable rippleDrawable = new RippleDrawable(
rippleDrawable.setColor(rippleColorStateList); rippleColorStateList, null, null
);
button.setBackground(rippleDrawable);
button.setOnClickListener((v) -> { button.setOnClickListener((v) -> {
handler.apply(); handler.apply();
@@ -121,7 +122,7 @@ public final class NewSegmentLayout extends FrameLayout {
} }
@FunctionalInterface @FunctionalInterface
public interface ButtonOnClickHandlerFunction { private interface ButtonOnClickHandlerFunction {
void apply(); void apply();
} }
} }

View File

@@ -1,7 +1,5 @@
package app.revanced.extension.youtube.sponsorblock.ui; package app.revanced.extension.youtube.sponsorblock.ui;
import static app.revanced.extension.shared.Utils.getResourceIdentifier;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;

View File

@@ -7,8 +7,6 @@ import android.os.Handler
import android.os.Looper import android.os.Looper
import android.util.TypedValue import android.util.TypedValue
import android.view.HapticFeedbackConstants import android.view.HapticFeedbackConstants
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout import android.widget.RelativeLayout
import android.widget.TextView import android.widget.TextView
import app.revanced.extension.shared.StringRef.str import app.revanced.extension.shared.StringRef.str
@@ -59,8 +57,8 @@ class SwipeControlsOverlayLayout(
val compoundIconPadding = 4.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP) val compoundIconPadding = 4.applyDimension(context, TypedValue.COMPLEX_UNIT_DIP)
feedbackTextView = TextView(context).apply { feedbackTextView = TextView(context).apply {
layoutParams = LayoutParams( layoutParams = LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
).apply { ).apply {
addRule(CENTER_IN_PARENT, TRUE) addRule(CENTER_IN_PARENT, TRUE)
setPadding( setPadding(
@@ -91,7 +89,7 @@ class SwipeControlsOverlayLayout(
private val feedbackHideHandler = Handler(Looper.getMainLooper()) private val feedbackHideHandler = Handler(Looper.getMainLooper())
private val feedbackHideCallback = Runnable { private val feedbackHideCallback = Runnable {
feedbackTextView.visibility = View.GONE feedbackTextView.visibility = GONE
} }
/** /**

View File

@@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M
org.gradle.parallel = true org.gradle.parallel = true
android.useAndroidX = true android.useAndroidX = true
kotlin.code.style = official kotlin.code.style = official
version = 5.0.0-dev.4 version = 5.2.0-dev.5

View File

@@ -503,6 +503,10 @@ public final class app/revanced/patches/reddit/customclients/sync/syncforreddit/
public static final fun getUseUserEndpointPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getUseUserEndpointPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
public final class app/revanced/patches/reddit/customclients/sync/syncforreddit/fix/video/FixVideoDownloadsPatchKt {
public static final fun getFixVideoDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatchKt { public final class app/revanced/patches/reddit/customclients/syncforreddit/fix/video/FixVideoDownloadsPatchKt {
public static final fun getFixVideoDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getFixVideoDownloadsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
} }
@@ -1324,6 +1328,7 @@ public final class app/revanced/patches/youtube/misc/playservice/VersionCheckPat
public static final fun is_19_36_or_greater ()Z public static final fun is_19_36_or_greater ()Z
public static final fun is_19_41_or_greater ()Z public static final fun is_19_41_or_greater ()Z
public static final fun is_19_43_or_greater ()Z public static final fun is_19_43_or_greater ()Z
public static final fun is_19_46_or_greater ()Z
} }
public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt { public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt {
@@ -1365,11 +1370,9 @@ public final class app/revanced/patches/youtube/shared/FingerprintsKt {
} }
public final class app/revanced/patches/youtube/video/information/VideoInformationPatchKt { public final class app/revanced/patches/youtube/video/information/VideoInformationPatchKt {
public static final fun getSetPlaybackSpeedClassFieldReference ()Ljava/lang/String;
public static final fun getSetPlaybackSpeedContainerClassFieldReference ()Ljava/lang/String;
public static final fun getSetPlaybackSpeedMethodReference ()Ljava/lang/String;
public static final fun getVideoInformationPatch ()Lapp/revanced/patcher/patch/BytecodePatch; public static final fun getVideoInformationPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
public static final fun userSelectedPlaybackSpeedHook (Ljava/lang/String;Ljava/lang/String;)V public static final fun userSelectedPlaybackSpeedHook (Ljava/lang/String;Ljava/lang/String;)V
public static final fun videoSpeedChangedHook (Ljava/lang/String;Ljava/lang/String;)V
public static final fun videoTimeHook (Ljava/lang/String;Ljava/lang/String;)V public static final fun videoTimeHook (Ljava/lang/String;Ljava/lang/String;)V
} }
@@ -1444,10 +1447,12 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I public static final fun indexOfFirstInstructionOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I
public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I
public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;ILkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I
public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;)I public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;)I
public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I public static final fun indexOfFirstInstructionReversed (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I
public static synthetic fun indexOfFirstInstructionReversed$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionReversed$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I
public static synthetic fun indexOfFirstInstructionReversed$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionReversed$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)I
public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Lcom/android/tools/smali/dexlib2/Opcode;)I
public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;)I public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;)I
public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I public static final fun indexOfFirstInstructionReversedOrThrow (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lkotlin/jvm/functions/Function1;)I
public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I public static synthetic fun indexOfFirstInstructionReversedOrThrow$default (Lcom/android/tools/smali/dexlib2/iface/Method;Ljava/lang/Integer;Lcom/android/tools/smali/dexlib2/Opcode;ILjava/lang/Object;)I

View File

@@ -1,3 +1,5 @@
package app.revanced.patches.facebook.ads.mainfeed
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode

View File

@@ -4,14 +4,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import baseModelMapperFingerprint
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
import getSponsoredDataModelTemplateFingerprint
import getStoryVisibilityFingerprint
@Suppress("unused") @Suppress("unused")
val hideSponsoredStoriesPatch = bytecodePatch( val hideSponsoredStoriesPatch = bytecodePatch(

View File

@@ -4,7 +4,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
@Suppress("unused") @Suppress("unused")
val enableCustomTabsPatch = bytecodePatch( val enableCustomTabsPatch = bytecodePatch(

View File

@@ -4,7 +4,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
@Suppress("unused") @Suppress("unused")
val restoreHiddenBackUpWhileChargingTogglePatch = bytecodePatch( val restoreHiddenBackUpWhileChargingTogglePatch = bytecodePatch(

View File

@@ -5,7 +5,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
@Suppress("unused") @Suppress("unused")
val removeDeviceRestrictionsPatch = bytecodePatch( val removeDeviceRestrictionsPatch = bytecodePatch(

View File

@@ -4,7 +4,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
@Suppress("unused") @Suppress("unused")
val disableSwitchingEmojiToStickerPatch = bytecodePatch( val disableSwitchingEmojiToStickerPatch = bytecodePatch(

View File

@@ -7,7 +7,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Suppress("unused")
val hideGetPremiumPatch = bytecodePatch( val hideGetPremiumPatch = bytecodePatch(
name = "Hide 'Get Music Premium' label", name = "Hide 'Get Music Premium' label",
description = "Hides the \"Get Music Premium\" label from the account menu and settings.", description = "Hides the \"Get Music Premium\" label from the account menu and settings.",

View File

@@ -4,7 +4,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
@Suppress("unused")
val backgroundPlaybackPatch = bytecodePatch( val backgroundPlaybackPatch = bytecodePatch(
name = "Remove background playback restrictions", name = "Remove background playback restrictions",
description = "Removes restrictions on background playback, including playing kids videos in the background.", description = "Removes restrictions on background playback, including playing kids videos in the background.",

View File

@@ -7,7 +7,7 @@ import app.revanced.patcher.patch.bytecodePatch
val unlockProPatch = bytecodePatch( val unlockProPatch = bytecodePatch(
name = "Unlock pro", name = "Unlock pro",
) { ) {
compatibleWith("org.totschnig.myexpenses") compatibleWith("org.totschnig.myexpenses"("3.4.9"))
execute { execute {
isEnabledFingerprint.method.addInstructions( isEnabledFingerprint.method.addInstructions(

View File

@@ -10,6 +10,6 @@ val disablePiracyDetectionPatch = bytecodePatch(
execute { execute {
// Do not throw an error if the fingerprint is not resolved. // Do not throw an error if the fingerprint is not resolved.
// This is fine because new versions of the target app do not need this patch. // This is fine because new versions of the target app do not need this patch.
piracyDetectionFingerprint.method.addInstruction(0, "return-void") piracyDetectionFingerprint.methodOrNull?.addInstruction(0, "return-void")
} }
} }

View File

@@ -1,9 +1,11 @@
package app.revanced.patches.reddit.customclients.sync.detection.piracy package app.revanced.patches.reddit.customclients.sync.detection.piracy
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.Reference
internal val piracyDetectionFingerprint = fingerprint { internal val piracyDetectionFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
@@ -16,12 +18,9 @@ internal val piracyDetectionFingerprint = fingerprint {
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
) )
custom { method, _ -> custom { method, _ ->
method.implementation?.instructions?.any { method.implementation ?: return@custom false
if (it.opcode != Opcode.NEW_INSTANCE) return@any false method.instructions.any {
it.getReference<Reference>()?.toString() == "Lcom/github/javiersantos/piracychecker/PiracyChecker;"
val reference = (it as ReferenceInstruction).reference }
reference.toString() == "Lcom/github/javiersantos/piracychecker/PiracyChecker;"
} == true
} }
} }

View File

@@ -63,20 +63,20 @@ val spoofClientPatch = spoofClientPatch(
val randomName = (0..100000).random() val randomName = (0..100000).random()
val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)" val userAgent = "$randomName:app.revanced.$randomName:v1.0.0 (by /u/revanced)"
imgurImageAPIFingerprint.method.replaceInstruction( getUserAgentFingerprint.method.replaceInstruction(
0, 0,
""" """
const-string v0, "$userAgent" const-string v0, "$userAgent"
return-object v0 return-object v0
""", """,
) )
// endregion // endregion
// region Patch Imgur API URL. // region Patch Imgur API URL.
val apiUrlIndex = getUserAgentFingerprint.stringMatches!!.first().index val apiUrlIndex = imgurImageAPIFingerprint.stringMatches!!.first().index
getUserAgentFingerprint.method.replaceInstruction( imgurImageAPIFingerprint.method.replaceInstruction(
apiUrlIndex, apiUrlIndex,
"const-string v1, \"https://api.imgur.com/3/image\"", "const-string v1, \"https://api.imgur.com/3/image\"",
) )

View File

@@ -6,8 +6,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.reddit.customclients.RESOLVE_S_LINK_METHOD import app.revanced.patches.reddit.customclients.RESOLVE_S_LINK_METHOD
import app.revanced.patches.reddit.customclients.SET_ACCESS_TOKEN_METHOD import app.revanced.patches.reddit.customclients.SET_ACCESS_TOKEN_METHOD
import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.getOAuthAccessTokenFingerprint
import app.revanced.patches.reddit.customclients.boostforreddit.fix.slink.handleNavigationFingerprint
import app.revanced.patches.reddit.customclients.fixSLinksPatch import app.revanced.patches.reddit.customclients.fixSLinksPatch
import app.revanced.patches.reddit.customclients.sync.syncforreddit.extension.sharedExtensionPatch import app.revanced.patches.reddit.customclients.sync.syncforreddit.extension.sharedExtensionPatch
@@ -26,7 +24,7 @@ val fixSLinksPatch = fixSLinksPatch(
execute { execute {
// region Patch navigation handler. // region Patch navigation handler.
handleNavigationFingerprint.method.apply { linkHelperOpenLinkFingerprint.method.apply {
val urlRegister = "p3" val urlRegister = "p3"
val tempRegister = "v2" val tempRegister = "v2"
@@ -46,7 +44,7 @@ val fixSLinksPatch = fixSLinksPatch(
// region Patch set access token. // region Patch set access token.
getOAuthAccessTokenFingerprint.method.addInstruction( setAuthorizationHeaderFingerprint.method.addInstruction(
0, 0,
"invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->$SET_ACCESS_TOKEN_METHOD", "invoke-static { p0 }, $EXTENSION_CLASS_DESCRIPTOR->$SET_ACCESS_TOKEN_METHOD",
) )

View File

@@ -1,4 +1,4 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.video package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode

View File

@@ -0,0 +1,56 @@
package app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.reddit.customclients.sync.syncforreddit.extension.sharedExtensionPatch
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/syncforreddit/FixRedditVideoDownloadPatch;"
private const val GET_LINKS_METHOD = "getLinks([B)[Ljava/lang/String;"
@Suppress("unused")
val fixVideoDownloadsPatch = bytecodePatch(
name = "Fix video downloads",
description = "Fixes a bug in Sync's MPD parser resulting in only the audio-track being saved.",
) {
dependsOn(sharedExtensionPatch)
compatibleWith(
"com.laurencedawson.reddit_sync",
"com.laurencedawson.reddit_sync.pro",
"com.laurencedawson.reddit_sync.dev",
)
execute {
val scanResult = parseRedditVideoNetworkResponseFingerprint.patternMatch!!
val newInstanceIndex = scanResult.startIndex
val invokeDirectIndex = scanResult.endIndex - 1
val buildResponseInstruction =
parseRedditVideoNetworkResponseFingerprint.method.getInstruction<Instruction35c>(invokeDirectIndex)
parseRedditVideoNetworkResponseFingerprint.method.addInstructions(
newInstanceIndex + 1,
"""
# Get byte array from response.
iget-object v2, p1, Lcom/android/volley/NetworkResponse;->data:[B
# Parse the videoUrl and audioUrl from the byte array.
invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->$GET_LINKS_METHOD
move-result-object v2
# Get videoUrl (Index 0).
const/4 v5, 0x0
aget-object v${buildResponseInstruction.registerE}, v2, v5
# Get audioUrl (Index 1).
const/4 v6, 0x1
aget-object v${buildResponseInstruction.registerF}, v2, v6
# Register E and F are used to build the response.
""",
)
}
}

View File

@@ -1,56 +1,18 @@
package app.revanced.patches.reddit.customclients.syncforreddit.fix.video package app.revanced.patches.reddit.customclients.syncforreddit.fix.video
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.reddit.customclients.sync.syncforreddit.extension.sharedExtensionPatch
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/syncforreddit/FixRedditVideoDownloadPatch;"
private const val GET_LINKS_METHOD = "getLinks([B)[Ljava/lang/String;"
@Deprecated(
message = "Patch was move to a different package",
ReplaceWith("app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video.fixVideoDownloadsPatch")
)
@Suppress("unused") @Suppress("unused")
val fixVideoDownloadsPatch = bytecodePatch( val fixVideoDownloadsPatch = bytecodePatch {
name = "Fix video downloads", dependsOn(app.revanced.patches.reddit.customclients.sync.syncforreddit.fix.video.fixVideoDownloadsPatch)
description = "Fixes a bug in Sync's MPD parser resulting in only the audio-track being saved.",
) {
dependsOn(sharedExtensionPatch)
compatibleWith( compatibleWith(
"com.laurencedawson.reddit_sync", "com.laurencedawson.reddit_sync",
"com.laurencedawson.reddit_sync.pro", "com.laurencedawson.reddit_sync.pro",
"com.laurencedawson.reddit_sync.dev", "com.laurencedawson.reddit_sync.dev",
) )
}
execute {
val scanResult = parseRedditVideoNetworkResponseFingerprint.patternMatch!!
val newInstanceIndex = scanResult.startIndex
val invokeDirectIndex = scanResult.endIndex - 1
val buildResponseInstruction =
parseRedditVideoNetworkResponseFingerprint.method.getInstruction<Instruction35c>(invokeDirectIndex)
parseRedditVideoNetworkResponseFingerprint.method.addInstructions(
newInstanceIndex + 1,
"""
# Get byte array from response.
iget-object v2, p1, Lcom/android/volley/NetworkResponse;->data:[B
# Parse the videoUrl and audioUrl from the byte array.
invoke-static { v2 }, $EXTENSION_CLASS_DESCRIPTOR->$GET_LINKS_METHOD
move-result-object v2
# Get videoUrl (Index 0).
const/4 v5, 0x0
aget-object v${buildResponseInstruction.registerE}, v2, v5
# Get audioUrl (Index 1).
const/4 v6, 0x1
aget-object v${buildResponseInstruction.registerF}, v2, v6
# Register E and F are used to build the response.
""",
)
}
}

View File

@@ -20,7 +20,7 @@ fun sharedExtensionPatch(
extendWith("extensions/shared.rve") extendWith("extensions/shared.rve")
execute { execute {
if (classBy { EXTENSION_CLASS_DESCRIPTOR in it.type } == null) { if (classes.none { EXTENSION_CLASS_DESCRIPTOR == it.type }) {
throw PatchException( throw PatchException(
"Shared extension has not been merged yet. This patch can not succeed without merging it.", "Shared extension has not been merged yet. This patch can not succeed without merging it.",
) )
@@ -35,7 +35,7 @@ fun sharedExtensionPatch(
*/ */
fun getCurrentJarFilePath(): String { fun getCurrentJarFilePath(): String {
val className = object {}::class.java.enclosingClass.name.replace('.', '/') + ".class" val className = object {}::class.java.enclosingClass.name.replace('.', '/') + ".class"
val classUrl = object {}::class.java.classLoader.getResource(className) val classUrl = object {}::class.java.classLoader?.getResource(className)
if (classUrl != null) { if (classUrl != null) {
val urlString = classUrl.toString() val urlString = classUrl.toString()

View File

@@ -21,7 +21,7 @@ internal val createTabsFingerprint = fingerprint {
if (reference.definingClass != ACTIVITY_TAB_DESCRIPTOR) return@any false if (reference.definingClass != ACTIVITY_TAB_DESCRIPTOR) return@any false
if (reference.returnType != "[${ACTIVITY_TAB_DESCRIPTOR}") return@any false if (reference.returnType != "[${ACTIVITY_TAB_DESCRIPTOR}") return@any false
true true
} ?: false } == true
} }
} }
@@ -42,7 +42,7 @@ internal val showNotificationFingerprint = fingerprint {
} }
} }
true true
} ?: false } == true
} }
} }

View File

@@ -5,8 +5,8 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch
import app.revanced.patches.tiktok.misc.settings.settingsPatch
import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint
import app.revanced.patches.twitch.misc.settings.settingsPatch
import app.revanced.util.findMutableMethodOf import app.revanced.util.findMutableMethodOf
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction

View File

@@ -11,7 +11,6 @@ import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
import app.revanced.patches.twitch.misc.settings.PreferenceScreen import app.revanced.patches.twitch.misc.settings.PreferenceScreen
import app.revanced.patches.twitch.misc.settings.settingsPatch import app.revanced.patches.twitch.misc.settings.settingsPatch
@Suppress("unused")
val audioAdsPatch = bytecodePatch( val audioAdsPatch = bytecodePatch(
name = "Block audio ads", name = "Block audio ads",
description = "Blocks audio ads in streams and VODs.", description = "Blocks audio ads in streams and VODs.",

View File

@@ -9,7 +9,6 @@ import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
import app.revanced.patches.twitch.misc.settings.PreferenceScreen import app.revanced.patches.twitch.misc.settings.PreferenceScreen
import app.revanced.patches.twitch.misc.settings.settingsPatch import app.revanced.patches.twitch.misc.settings.settingsPatch
@Suppress("unused")
val embeddedAdsPatch = bytecodePatch( val embeddedAdsPatch = bytecodePatch(
name = "Block embedded ads", name = "Block embedded ads",
description = "Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.", description = "Blocks embedded stream ads using services like Luminous or PurpleAdBlocker.",

View File

@@ -12,7 +12,6 @@ import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
import app.revanced.patches.twitch.misc.settings.PreferenceScreen import app.revanced.patches.twitch.misc.settings.PreferenceScreen
import app.revanced.patches.twitch.misc.settings.settingsPatch import app.revanced.patches.twitch.misc.settings.settingsPatch
@Suppress("unused")
val showDeletedMessagesPatch = bytecodePatch( val showDeletedMessagesPatch = bytecodePatch(
name = "Show deleted messages", name = "Show deleted messages",
description = "Shows deleted chat messages behind a clickable spoiler.", description = "Shows deleted chat messages behind a clickable spoiler.",

View File

@@ -11,7 +11,6 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.twitch.misc.settings.PreferenceScreen import app.revanced.patches.twitch.misc.settings.PreferenceScreen
import app.revanced.patches.twitch.misc.settings.settingsPatch import app.revanced.patches.twitch.misc.settings.settingsPatch
@Suppress("unused")
val autoClaimChannelPointsPatch = bytecodePatch( val autoClaimChannelPointsPatch = bytecodePatch(
name = "Auto claim channel points", name = "Auto claim channel points",
description = "Automatically claim Channel Points.", description = "Automatically claim Channel Points.",

View File

@@ -9,7 +9,6 @@ import app.revanced.patches.twitch.misc.extension.sharedExtensionPatch
import app.revanced.patches.twitch.misc.settings.PreferenceScreen import app.revanced.patches.twitch.misc.settings.PreferenceScreen
import app.revanced.patches.twitch.misc.settings.settingsPatch import app.revanced.patches.twitch.misc.settings.settingsPatch
@Suppress("unused")
val debugModePatch = bytecodePatch( val debugModePatch = bytecodePatch(
name = "Debug mode", name = "Debug mode",
description = "Enables Twitch's internal debugging mode.", description = "Enables Twitch's internal debugging mode.",

View File

@@ -47,18 +47,22 @@ val jsonHookPatch = bytecodePatch(
dependsOn(sharedExtensionPatch) dependsOn(sharedExtensionPatch)
execute { execute {
val jsonFactoryClassDef = jsonHookPatchFingerprint.apply { jsonHookPatchFingerprint.apply {
// Make sure the extension is present. // Make sure the extension is present.
val jsonHookPatch = classBy { classDef -> classDef.type == JSON_HOOK_PATCH_CLASS_DESCRIPTOR } val jsonHookPatch = classBy { classDef -> classDef.type == JSON_HOOK_PATCH_CLASS_DESCRIPTOR }
?: throw PatchException("Could not find the extension.") ?: throw PatchException("Could not find the extension.")
matchOrNull(jsonHookPatch.immutableClass) matchOrNull(jsonHookPatch.immutableClass)
?: throw PatchException("Unexpected extension.") ?: throw PatchException("Unexpected extension.")
}.originalClassDef // Conveniently find the type to hook a method in, via a named field. }
.fields
.firstOrNull { it.name == "JSON_FACTORY" } val jsonFactoryClassDef =
?.type loganSquareFingerprint.originalClassDef // Conveniently find the type to hook a method in, via a named field.
.let { type -> classes.find { it.type == type } } ?: throw PatchException("Could not find required class.") .fields
.firstOrNull { it.name == "JSON_FACTORY" }
?.type
.let { type -> classes.find { it.type == type } }
?: throw PatchException("Could not find required class.")
// Hook the methods first parameter. // Hook the methods first parameter.
jsonInputStreamFingerprint.match(jsonFactoryClassDef).method.addInstructions( jsonInputStreamFingerprint.match(jsonFactoryClassDef).method.addInstructions(

View File

@@ -9,6 +9,7 @@ import app.revanced.patcher.patch.stringOption
import app.revanced.patches.shared.misc.mapping.get import app.revanced.patches.shared.misc.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
@@ -39,7 +40,10 @@ val changeLinkSharingDomainPatch = bytecodePatch(
name = "Change link sharing domain", name = "Change link sharing domain",
description = "Replaces the domain name of Twitter links when sharing them.", description = "Replaces the domain name of Twitter links when sharing them.",
) { ) {
dependsOn(changeLinkSharingDomainResourcePatch) dependsOn(
changeLinkSharingDomainResourcePatch,
sharedExtensionPatch,
)
compatibleWith("com.twitter.android") compatibleWith("com.twitter.android")
@@ -52,7 +56,6 @@ val changeLinkSharingDomainPatch = bytecodePatch(
) )
execute { execute {
val replacementIndex = val replacementIndex =
linkSharingDomainFingerprint.stringMatches!!.first().index linkSharingDomainFingerprint.stringMatches!!.first().index
val domainRegister = val domainRegister =

View File

@@ -2,6 +2,7 @@ package app.revanced.patches.twitter.misc.links
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.twitter.misc.extension.sharedExtensionPatch
@Suppress("unused") @Suppress("unused")
val openLinksWithAppChooserPatch = bytecodePatch( val openLinksWithAppChooserPatch = bytecodePatch(
@@ -10,6 +11,8 @@ val openLinksWithAppChooserPatch = bytecodePatch(
"As a result you can select a browser to open the link with.", "As a result you can select a browser to open the link with.",
use = false, use = false,
) { ) {
dependsOn(sharedExtensionPatch)
compatibleWith("com.twitter.android"("10.48.0-release.0")) compatibleWith("com.twitter.android"("10.48.0-release.0"))
execute { execute {

View File

@@ -3,9 +3,9 @@ package app.revanced.patches.vsco.misc.pro
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.bytecodePatch
@Deprecated("This patch is deprecated because it does not work anymore and will be removed in the future.")
@Suppress("unused") @Suppress("unused")
val unlockProPatch = bytecodePatch( val unlockProPatch = bytecodePatch(
name = "Unlock pro",
description = "Unlocks pro features.", description = "Unlocks pro features.",
) { ) {
compatibleWith("com.vsco.cam"("345")) compatibleWith("com.vsco.cam"("345"))

View File

@@ -75,6 +75,7 @@ val hideAdsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -31,6 +31,7 @@ val hideGetPremiumPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -11,7 +11,6 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@Suppress("unused")
val videoAdsPatch = bytecodePatch( val videoAdsPatch = bytecodePatch(
name = "Video ads", name = "Video ads",
description = "Adds an option to remove ads in the video player.", description = "Adds an option to remove ads in the video player.",
@@ -30,6 +29,7 @@ val videoAdsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -59,6 +59,7 @@ val copyVideoUrlPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -11,7 +11,6 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@Suppress("unused")
val removeViewerDiscretionDialogPatch = bytecodePatch( val removeViewerDiscretionDialogPatch = bytecodePatch(
name = "Remove viewer discretion dialog", name = "Remove viewer discretion dialog",
description = "Adds an option to remove the dialog that appears when opening a video that has been age-restricted " + description = "Adds an option to remove the dialog that appears when opening a video that has been age-restricted " +
@@ -31,6 +30,7 @@ val removeViewerDiscretionDialogPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -74,6 +74,7 @@ val downloadsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -11,7 +11,6 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@Suppress("unused")
val disablePreciseSeekingGesturePatch = bytecodePatch( val disablePreciseSeekingGesturePatch = bytecodePatch(
name = "Disable precise seeking gesture", name = "Disable precise seeking gesture",
description = "Adds an option to disable precise seeking when swiping up on the seekbar.", description = "Adds an option to disable precise seeking when swiping up on the seekbar.",
@@ -30,6 +29,7 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -14,7 +14,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@Suppress("unused")
val enableSeekbarTappingPatch = bytecodePatch( val enableSeekbarTappingPatch = bytecodePatch(
name = "Seekbar tapping", name = "Seekbar tapping",
description = "Adds an option to enable tap-to-seek on the seekbar of the video player.", description = "Adds an option to enable tap-to-seek on the seekbar of the video player.",
@@ -33,6 +32,7 @@ val enableSeekbarTappingPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -17,12 +17,10 @@ import app.revanced.util.getReference
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
internal const val EXTENSION_METHOD_DESCRIPTOR = internal const val EXTENSION_METHOD_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/SlideToSeekPatch;->isSlideToSeekDisabled(Z)Z" "Lapp/revanced/extension/youtube/patches/SlideToSeekPatch;->isSlideToSeekDisabled(Z)Z"
@Suppress("unused")
val enableSlideToSeekPatch = bytecodePatch( val enableSlideToSeekPatch = bytecodePatch(
name = "Enable slide to seek", name = "Enable slide to seek",
description = "Adds an option to enable slide to seek " + description = "Adds an option to enable slide to seek " +
@@ -44,6 +42,7 @@ val enableSlideToSeekPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -16,7 +16,6 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;" "Lapp/revanced/extension/youtube/patches/SeekbarThumbnailsPatch;"
@Suppress("unused")
val seekbarThumbnailsPatch = bytecodePatch( val seekbarThumbnailsPatch = bytecodePatch(
name = "Seekbar thumbnails", name = "Seekbar thumbnails",
description = "Adds an option to use high quality fullscreen seekbar thumbnails. " + description = "Adds an option to use high quality fullscreen seekbar thumbnails. " +
@@ -36,6 +35,7 @@ val seekbarThumbnailsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
) )
) )

View File

@@ -71,6 +71,7 @@ val swipeControlsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -10,7 +10,6 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.subtitleButtonControllerFingerprint import app.revanced.patches.youtube.shared.subtitleButtonControllerFingerprint
@Suppress("unused")
val autoCaptionsPatch = bytecodePatch( val autoCaptionsPatch = bytecodePatch(
name = "Disable auto captions", name = "Disable auto captions",
description = "Adds an option to disable captions from being automatically enabled.", description = "Adds an option to disable captions from being automatically enabled.",
@@ -29,6 +28,7 @@ val autoCaptionsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -41,7 +41,17 @@ val customBrandingPatch = resourcePatch(
) { ) {
dependsOn(versionCheckPatch) dependsOn(versionCheckPatch)
compatibleWith("com.google.android.youtube") compatibleWith(
"com.google.android.youtube"(
"18.38.44",
"18.49.37",
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
),
)
val appName by stringOption( val appName by stringOption(
key = "appName", key = "appName",

View File

@@ -3,9 +3,12 @@ package app.revanced.patches.youtube.layout.branding.header
import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.PatchException
import app.revanced.patcher.patch.resourcePatch import app.revanced.patcher.patch.resourcePatch
import app.revanced.patcher.patch.stringOption import app.revanced.patcher.patch.stringOption
import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.ResourceGroup import app.revanced.util.ResourceGroup
import app.revanced.util.Utils.trimIndentMultiline import app.revanced.util.Utils.trimIndentMultiline
import app.revanced.util.copyResources import app.revanced.util.copyResources
import app.revanced.util.findElementByAttributeValueOrThrow
import java.io.File import java.io.File
private const val HEADER_FILE_NAME = "yt_wordmark_header" private const val HEADER_FILE_NAME = "yt_wordmark_header"
@@ -34,7 +37,19 @@ val changeHeaderPatch = resourcePatch(
description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.", description = "Applies a custom header in the top left corner within the app. Defaults to the ReVanced header.",
use = false, use = false,
) { ) {
compatibleWith("com.google.android.youtube") dependsOn(versionCheckPatch)
compatibleWith(
"com.google.android.youtube"(
"18.38.44",
"18.49.37",
"19.16.39",
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
)
)
val header by stringOption( val header by stringOption(
key = "header", key = "header",
@@ -79,7 +94,7 @@ val changeHeaderPatch = resourcePatch(
/** /**
* A function that overwrites both header variants in the target resource directories. * A function that overwrites both header variants in the target resource directories.
*/ */
val overwriteFromTo: (String, String) -> Unit = { from: String, to: String -> fun overwriteFromTo(from: String, to: String) {
targetResourceDirectories.forEach { directory -> targetResourceDirectories.forEach { directory ->
variants.forEach { variant -> variants.forEach { variant ->
val fromPath = directory.resolve("${from}_$variant.png") val fromPath = directory.resolve("${from}_$variant.png")
@@ -91,23 +106,28 @@ val changeHeaderPatch = resourcePatch(
} }
// Functions to overwrite the header to the different variants. // Functions to overwrite the header to the different variants.
val toPremium = { overwriteFromTo(PREMIUM_HEADER_FILE_NAME, HEADER_FILE_NAME) } fun toPremium() { overwriteFromTo(PREMIUM_HEADER_FILE_NAME, HEADER_FILE_NAME) }
val toHeader = { overwriteFromTo(HEADER_FILE_NAME, PREMIUM_HEADER_FILE_NAME) } fun toHeader() { overwriteFromTo(HEADER_FILE_NAME, PREMIUM_HEADER_FILE_NAME) }
val toReVanced = { fun toReVanced() {
// Copy the ReVanced header to the resource directories. // Copy the ReVanced header to the resource directories.
targetResourceFiles.forEach { copyResources("change-header/revanced", it) } targetResourceFiles.forEach { copyResources("change-header/revanced", it) }
// Overwrite the premium with the custom header as well. // Overwrite the premium with the custom header as well.
toHeader() toHeader()
} }
val toReVancedBorderless = { fun toReVancedBorderless() {
// Copy the ReVanced borderless header to the resource directories. // Copy the ReVanced borderless header to the resource directories.
targetResourceFiles.forEach { copyResources("change-header/revanced-borderless", it) } targetResourceFiles.forEach {
copyResources(
"change-header/revanced-borderless",
it
)
}
// Overwrite the premium with the custom header as well. // Overwrite the premium with the custom header as well.
toHeader() toHeader()
} }
val toCustom = { fun toCustom() {
val sourceFolders = File(header!!).listFiles { file -> file.isDirectory } val sourceFolders = File(header!!).listFiles { file -> file.isDirectory }
?: throw PatchException("The provided path is not a directory: $header") ?: throw PatchException("The provided path is not a directory: $header")
@@ -136,11 +156,42 @@ val changeHeaderPatch = resourcePatch(
} }
when (header) { when (header) {
HEADER_OPTION -> toHeader HEADER_OPTION -> toHeader()
PREMIUM_HEADER_OPTION -> toPremium PREMIUM_HEADER_OPTION -> toPremium()
REVANCED_HEADER_OPTION -> toReVanced REVANCED_HEADER_OPTION -> toReVanced()
REVANCED_BORDERLESS_HEADER_OPTION -> toReVancedBorderless REVANCED_BORDERLESS_HEADER_OPTION -> toReVancedBorderless()
else -> toCustom else -> toCustom()
}() }
// Fix 19.25+ A/B layout with different header icons:
// yt_ringo2_wordmark_header, yt_ringo2_premium_wordmark_header
//
// These images are webp and not png, so overwriting them is not so simple.
// Instead change styles.xml to use the old drawable resources.
if (is_19_25_or_greater) {
document("res/values/styles.xml").use { document ->
arrayOf(
"CairoLightThemeRingo2Updates" to variants[0],
"CairoDarkThemeRingo2Updates" to variants[1]
).forEach { (styleName, theme) ->
val style = document.childNodes.findElementByAttributeValueOrThrow(
"name",
styleName,
)
val drawable = "@drawable/${HEADER_FILE_NAME}_${theme}"
arrayOf(
"ytWordmarkHeader",
"ytPremiumWordmarkHeader"
).forEach { itemName ->
style.childNodes.findElementByAttributeValueOrThrow(
"name",
itemName,
).textContent = drawable
}
}
}
}
} }
} }

View File

@@ -10,7 +10,6 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
@Suppress("unused")
val hideButtonsPatch = resourcePatch( val hideButtonsPatch = resourcePatch(
name = "Hide video action buttons", name = "Hide video action buttons",
description = "Adds options to hide action buttons (such as the Download button) under videos.", description = "Adds options to hide action buttons (such as the Download button) under videos.",
@@ -29,6 +28,7 @@ val hideButtonsPatch = resourcePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -19,7 +19,6 @@ import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
internal const val EXTENSION_CLASS_DESCRIPTOR = internal const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/NavigationButtonsPatch;" "Lapp/revanced/extension/youtube/patches/NavigationButtonsPatch;"
@@ -43,6 +42,7 @@ val navigationButtonsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -60,6 +60,7 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -62,6 +62,7 @@ val hideEndscreenCardsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -17,7 +17,6 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal const val EXTENSION_CLASS_DESCRIPTOR = internal const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/DisableFullscreenAmbientModePatch;" "Lapp/revanced/extension/youtube/patches/DisableFullscreenAmbientModePatch;"
@Suppress("unused")
val disableFullscreenAmbientModePatch = bytecodePatch( val disableFullscreenAmbientModePatch = bytecodePatch(
name = "Disable fullscreen ambient mode", name = "Disable fullscreen ambient mode",
description = "Adds an option to disable the ambient mode when in fullscreen.", description = "Adds an option to disable the ambient mode when in fullscreen.",
@@ -36,6 +35,7 @@ val disableFullscreenAmbientModePatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -107,7 +107,6 @@ private const val CUSTOM_FILTER_CLASS_NAME =
private const val KEYWORD_FILTER_CLASS_NAME = private const val KEYWORD_FILTER_CLASS_NAME =
"Lapp/revanced/extension/youtube/patches/components/KeywordContentFilter;" "Lapp/revanced/extension/youtube/patches/components/KeywordContentFilter;"
@Suppress("unused")
val hideLayoutComponentsPatch = bytecodePatch( val hideLayoutComponentsPatch = bytecodePatch(
name = "Hide layout components", name = "Hide layout components",
description = "Adds options to hide general layout components.", description = "Adds options to hide general layout components.",
@@ -129,6 +128,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -63,6 +63,7 @@ val hideInfoCardsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -11,7 +11,6 @@ import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@Suppress("unused")
val hidePlayerFlyoutMenuPatch = bytecodePatch( val hidePlayerFlyoutMenuPatch = bytecodePatch(
name = "Hide player flyout menu items", name = "Hide player flyout menu items",
description = "Adds options to hide menu items that appear when pressing the gear icon in the video player.", description = "Adds options to hide menu items that appear when pressing the gear icon in the video player.",
@@ -31,6 +30,7 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -17,7 +17,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/DisableRollingNumberAnimationsPatch;" "Lapp/revanced/extension/youtube/patches/DisableRollingNumberAnimationsPatch;"
@Suppress("unused")
val disableRollingNumberAnimationPatch = bytecodePatch( val disableRollingNumberAnimationPatch = bytecodePatch(
name = "Disable rolling number animations", name = "Disable rolling number animations",
description = "Adds an option to disable rolling number animations of video view count, user likes, and upload time.", description = "Adds an option to disable rolling number animations of video view count, user likes, and upload time.",
@@ -36,6 +35,7 @@ val disableRollingNumberAnimationPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -12,7 +12,6 @@ import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.seekbarFingerprint import app.revanced.patches.youtube.shared.seekbarFingerprint
import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint import app.revanced.patches.youtube.shared.seekbarOnDrawFingerprint
@Suppress("unused")
val hideSeekbarPatch = bytecodePatch( val hideSeekbarPatch = bytecodePatch(
name = "Hide seekbar", name = "Hide seekbar",
description = "Adds an option to hide the seekbar.", description = "Adds an option to hide the seekbar.",
@@ -32,6 +31,7 @@ val hideSeekbarPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -29,7 +29,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
internal var reelMultipleItemShelfId = -1L internal var reelMultipleItemShelfId = -1L
private set private set
@@ -189,9 +188,13 @@ val hideShortsComponentsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )
hideShortsAppShortcutOption()
hideShortsWidgetOption()
execute { execute {
// region Hide the Shorts shelf. // region Hide the Shorts shelf.

View File

@@ -60,6 +60,7 @@ val disableSuggestedVideoEndScreenPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -9,7 +9,6 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@Suppress("unused")
val hideTimestampPatch = bytecodePatch( val hideTimestampPatch = bytecodePatch(
name = "Hide timestamp", name = "Hide timestamp",
description = "Adds an option to hide the timestamp in the bottom left of the video player.", description = "Adds an option to hide the timestamp in the bottom left of the video player.",
@@ -28,6 +27,7 @@ val hideTimestampPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -43,6 +43,7 @@ internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L
internal val miniplayerModernConstructorFingerprint = fingerprint { internal val miniplayerModernConstructorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
@@ -50,6 +51,12 @@ internal val miniplayerModernConstructorFingerprint = fingerprint {
literal { 45623000L } literal { 45623000L }
} }
internal val miniplayerOnCloseHandlerFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z")
literal { MINIPLAYER_DISABLED_FEATURE_KEY }
}
/** /**
* Matches using the class found in [miniplayerModernViewParentFingerprint]. * Matches using the class found in [miniplayerModernViewParentFingerprint].
*/ */

View File

@@ -135,8 +135,7 @@ private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/
@Suppress("unused") @Suppress("unused")
val miniplayerPatch = bytecodePatch( val miniplayerPatch = bytecodePatch(
name = "Miniplayer", name = "Miniplayer",
description = "Adds options to change the in app minimized player. " + description = "Adds options to change the in app minimized player."
"Patching target 19.16+ adds modern miniplayers.",
) { ) {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,
@@ -147,8 +146,7 @@ val miniplayerPatch = bytecodePatch(
compatibleWith( compatibleWith(
"com.google.android.youtube"( "com.google.android.youtube"(
"18.38.44", // 18.49.37 // Could be supported, but no reason when 19.16 exists and has modern types.
"18.49.37",
// 19.14.43 // Incomplete code for modern miniplayers. // 19.14.43 // Incomplete code for modern miniplayers.
// 19.15.36 // Different code for handling subtitle texts and not worth supporting. // 19.15.36 // Different code for handling subtitle texts and not worth supporting.
"19.16.39", // First with modern miniplayers. "19.16.39", // First with modern miniplayers.
@@ -170,6 +168,7 @@ val miniplayerPatch = bytecodePatch(
// 19.33.35 // 19.33.35
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )
@@ -178,58 +177,60 @@ val miniplayerPatch = bytecodePatch(
val preferences = mutableSetOf<BasePreference>() val preferences = mutableSetOf<BasePreference>()
if (!is_19_16_or_greater) {
preferences += ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
entriesKey = "revanced_miniplayer_type_legacy_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_entry_values",
)
} else {
preferences += ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
)
if (is_19_25_or_greater) {
if (!is_19_29_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_double_tap_action")
}
preferences += SwitchPreference("revanced_miniplayer_drag_and_drop")
}
preferences +=
if (is_19_43_or_greater) { if (is_19_43_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_horizontal_drag") ListPreference(
} "revanced_miniplayer_type",
summaryKey = null,
if (is_19_36_or_greater) { )
preferences += SwitchPreference("revanced_miniplayer_rounded_corners")
}
preferences += SwitchPreference("revanced_miniplayer_hide_subtext")
preferences += if (is_19_26_or_greater) {
SwitchPreference("revanced_miniplayer_hide_expand_close")
} else { } else {
SwitchPreference( ListPreference(
key = "revanced_miniplayer_hide_expand_close", "revanced_miniplayer_type",
titleKey = "revanced_miniplayer_hide_expand_close_legacy_title", summaryKey = null,
summaryOnKey = "revanced_miniplayer_hide_expand_close_legacy_summary_on", entriesKey = "revanced_miniplayer_type_legacy_entries",
summaryOffKey = "revanced_miniplayer_hide_expand_close_legacy_summary_off", entryValuesKey = "revanced_miniplayer_type_legacy_entry_values",
) )
} }
if (!is_19_26_or_greater) { if (is_19_25_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_hide_rewind_forward") if (!is_19_29_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_double_tap_action")
} }
preferences += SwitchPreference("revanced_miniplayer_drag_and_drop")
if (is_19_26_or_greater) {
preferences += TextPreference("revanced_miniplayer_width_dip", inputType = InputType.NUMBER)
}
preferences += TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER)
} }
if (is_19_43_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_horizontal_drag")
}
if (is_19_36_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_rounded_corners")
}
preferences += SwitchPreference("revanced_miniplayer_hide_subtext")
preferences += if (is_19_26_or_greater) {
SwitchPreference("revanced_miniplayer_hide_expand_close")
} else {
SwitchPreference(
key = "revanced_miniplayer_hide_expand_close",
titleKey = "revanced_miniplayer_hide_expand_close_legacy_title",
summaryOnKey = "revanced_miniplayer_hide_expand_close_legacy_summary_on",
summaryOffKey = "revanced_miniplayer_hide_expand_close_legacy_summary_off",
)
}
if (!is_19_26_or_greater) {
preferences += SwitchPreference("revanced_miniplayer_hide_rewind_forward")
}
if (is_19_26_or_greater) {
preferences += TextPreference("revanced_miniplayer_width_dip", inputType = InputType.NUMBER)
}
preferences += TextPreference("revanced_miniplayer_opacity", inputType = InputType.NUMBER)
PreferenceScreen.PLAYER.addPreferences( PreferenceScreen.PLAYER.addPreferences(
PreferenceScreenPreference( PreferenceScreenPreference(
key = "revanced_miniplayer_screen", key = "revanced_miniplayer_screen",
@@ -349,11 +350,6 @@ val miniplayerPatch = bytecodePatch(
it.method.insertLegacyTabletMiniplayerOverride(it.patternMatch!!.endIndex) it.method.insertLegacyTabletMiniplayerOverride(it.patternMatch!!.endIndex)
} }
if (!is_19_16_or_greater) {
// Return here, as patch below is only for the current versions of the app.
return@execute
}
// endregion // endregion
// region Enable modern miniplayer. // region Enable modern miniplayer.
@@ -379,13 +375,6 @@ val miniplayerPatch = bytecodePatch(
) )
} }
if (is_19_43_or_greater) {
miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"setHorizontalDrag",
)
}
if (is_19_25_or_greater) { if (is_19_25_or_greater) {
miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride( miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
MINIPLAYER_MODERN_FEATURE_LEGACY_KEY, MINIPLAYER_MODERN_FEATURE_LEGACY_KEY,
@@ -442,6 +431,18 @@ val miniplayerPatch = bytecodePatch(
) )
} }
if (is_19_43_or_greater) {
miniplayerOnCloseHandlerFingerprint.insertLiteralValueBooleanOverride(
MINIPLAYER_DISABLED_FEATURE_KEY,
"getMiniplayerOnCloseHandler"
)
miniplayerModernConstructorFingerprint.insertLiteralValueBooleanOverride(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"setHorizontalDrag",
)
}
// endregion // endregion
// region Fix 19.16 using mixed up drawables for tablet modern. // region Fix 19.16 using mixed up drawables for tablet modern.

View File

@@ -9,7 +9,6 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@Suppress("unused")
val playerPopupPanelsPatch = bytecodePatch( val playerPopupPanelsPatch = bytecodePatch(
name = "Disable player popup panels", name = "Disable player popup panels",
description = "Adds an option to disable panels (such as live chat) from opening automatically.", description = "Adds an option to disable panels (such as live chat) from opening automatically.",
@@ -28,6 +27,7 @@ val playerPopupPanelsPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -18,6 +18,7 @@ val playerControlsBackgroundPatch = resourcePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -58,6 +58,7 @@ val customPlayerOverlayOpacityPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -31,7 +31,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.sun.org.apache.bcel.internal.generic.InstructionConst.getInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch;" "Lapp/revanced/extension/youtube/patches/ReturnYouTubeDislikePatch;"
@@ -39,7 +38,6 @@ private const val EXTENSION_CLASS_DESCRIPTOR =
private const val FILTER_CLASS_DESCRIPTOR = private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;" "Lapp/revanced/extension/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;"
@Suppress("unused")
val returnYouTubeDislikePatch = bytecodePatch( val returnYouTubeDislikePatch = bytecodePatch(
name = "Return YouTube Dislike", name = "Return YouTube Dislike",
description = "Adds an option to show the dislike count of videos with Return YouTube Dislike.", description = "Adds an option to show the dislike count of videos with Return YouTube Dislike.",
@@ -61,6 +59,7 @@ val returnYouTubeDislikePatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -17,7 +17,6 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/WideSearchbarPatch;" "Lapp/revanced/extension/youtube/patches/WideSearchbarPatch;"
@Suppress("unused")
val wideSearchbarPatch = bytecodePatch( val wideSearchbarPatch = bytecodePatch(
name = "Wide searchbar", name = "Wide searchbar",
description = "Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.", description = "Adds an option to replace the search icon with a wide search bar. This will hide the YouTube logo when active.",
@@ -36,6 +35,7 @@ val wideSearchbarPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -48,3 +48,17 @@ internal val lithoLinearGradientFingerprint = fingerprint {
returns("Landroid/graphics/LinearGradient;") returns("Landroid/graphics/LinearGradient;")
parameters("F", "F", "F", "F", "[I", "[F") parameters("F", "F", "F", "F", "[I", "[F")
} }
internal const val launchScreenLayoutTypeLotteFeatureFlag = 268507948L
internal val launchScreenLayoutTypeFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
returns("V")
custom { method, _ ->
val firstParameter = method.parameterTypes.firstOrNull()
// 19.25 - 19.45
(firstParameter == "Lcom/google/android/apps/youtube/app/watchwhile/MainActivity;"
|| firstParameter == "Landroid/app/Activity;") // 19.46+
&& method.containsLiteralInstruction(launchScreenLayoutTypeLotteFeatureFlag)
}
}

View File

@@ -13,15 +13,24 @@ import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.youtube.layout.theme.lithoColorHookPatch import app.revanced.patches.youtube.layout.theme.lithoColorHookPatch
import app.revanced.patches.youtube.layout.theme.lithoColorOverrideHook import app.revanced.patches.youtube.layout.theme.lithoColorOverrideHook
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_23_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_46_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
import app.revanced.util.copyXmlNode
import app.revanced.util.findElementByAttributeValueOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import app.revanced.util.inputStreamFromBundledResource
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import org.w3c.dom.Element import org.w3c.dom.Element
import java.io.ByteArrayInputStream
import kotlin.use
internal var reelTimeBarPlayedColorId = -1L internal var reelTimeBarPlayedColorId = -1L
private set private set
@@ -30,6 +39,8 @@ internal var inlineTimeBarColorizedBarPlayedColorDarkId = -1L
internal var inlineTimeBarPlayedNotHighlightedColorId = -1L internal var inlineTimeBarPlayedNotHighlightedColorId = -1L
private set private set
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
private val seekbarColorResourcePatch = resourcePatch { private val seekbarColorResourcePatch = resourcePatch {
dependsOn( dependsOn(
settingsPatch, settingsPatch,
@@ -51,9 +62,8 @@ private val seekbarColorResourcePatch = resourcePatch {
"inline_time_bar_played_not_highlighted_color", "inline_time_bar_played_not_highlighted_color",
] ]
// Edit the resume playback drawable and replace the progress bar with a custom drawable // Modify the resume playback drawable and replace the progress bar with a custom drawable.
document("res/drawable/resume_playback_progressbar_drawable.xml").use { document -> document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
val layerList = document.getElementsByTagName("layer-list").item(0) as Element val layerList = document.getElementsByTagName("layer-list").item(0) as Element
val progressNode = layerList.getElementsByTagName("item").item(1) as Element val progressNode = layerList.getElementsByTagName("item").item(1) as Element
if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) { if (!progressNode.getAttributeNode("android:id").value.endsWith("progress")) {
@@ -66,9 +76,102 @@ private val seekbarColorResourcePatch = resourcePatch {
) )
scaleNode.replaceChild(replacementNode, shapeNode) scaleNode.replaceChild(replacementNode, shapeNode)
} }
if (!is_19_25_or_greater) {
return@execute
}
// Add attribute and styles for splash screen custom color.
// Using a style is the only way to selectively change just the seekbar fill color.
//
// Because the style colors must be hard coded for all color possibilities,
// instead of allowing 24 bit color the style is restricted to 9-bit (3 bits per color channel)
// and the style color closest to the users custom color is used for the splash screen.
arrayOf(
inputStreamFromBundledResource("seekbar/values", "attrs.xml")!! to "res/values/attrs.xml",
ByteArrayInputStream(create9BitSeekbarColorStyles().toByteArray()) to "res/values/styles.xml"
).forEach { (source, destination) ->
"resources".copyXmlNode(
document(source),
document(destination),
).close()
}
fun setSplashDrawablePathFillColor(xmlFileNames: Iterable<String>, vararg resourceNames: String) {
xmlFileNames.forEach { xmlFileName ->
document(xmlFileName).use { document ->
resourceNames.forEach { elementId ->
val element = document.childNodes.findElementByAttributeValueOrThrow(
"android:name",
elementId
)
val attribute = "android:fillColor"
if (!element.hasAttribute(attribute)) {
throw PatchException("Could not find $attribute for $elementId")
}
element.setAttribute(attribute, "?attr/$splashSeekbarColorAttributeName")
}
}
}
}
setSplashDrawablePathFillColor(
listOf(
"res/drawable/\$startup_animation_light__0.xml",
"res/drawable/\$startup_animation_dark__0.xml"
),
"_R_G_L_10_G_D_0_P_0"
)
if (!is_19_46_or_greater) {
// Resources removed in 19.46+
setSplashDrawablePathFillColor(
listOf(
"res/drawable/\$buenos_aires_animation_light__0.xml",
"res/drawable/\$buenos_aires_animation_dark__0.xml"
),
"_R_G_L_8_G_D_0_P_0"
)
}
} }
} }
/**
* Generate a style xml with all combinations of 9-bit colors.
*/
private fun create9BitSeekbarColorStyles(): String = StringBuilder().apply {
append("<?xml version=\"1.0\" encoding=\"utf-8\"?>")
append("<resources>\n")
for (red in 0..7) {
for (green in 0..7) {
for (blue in 0..7) {
val name = "${red}_${green}_${blue}"
fun roundTo3BitHex(channel8Bits: Int) =
(channel8Bits * 255 / 7).toString(16).padStart(2, '0')
val r = roundTo3BitHex(red)
val g = roundTo3BitHex(green)
val b = roundTo3BitHex(blue)
val color = "#ff$r$g$b"
append(
"""
<style name="splash_seekbar_color_style_$name">
<item name="$splashSeekbarColorAttributeName">$color</item>
</style>
"""
)
}
}
}
append("</resources>")
}.toString()
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/theme/SeekbarColorPatch;"
val seekbarColorPatch = bytecodePatch( val seekbarColorPatch = bytecodePatch(
@@ -117,27 +220,73 @@ val seekbarColorPatch = bytecodePatch(
} }
} }
if (is_19_23_or_greater) { lithoColorOverrideHook(EXTENSION_CLASS_DESCRIPTOR, "getLithoColor")
playerSeekbarGradientConfigFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG) if (!is_19_25_or_greater) {
return@execute
}
// 19.25+ changes
playerSeekbarGradientConfigFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG)
val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(resultIndex).registerA
addInstructions(
resultIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z
move-result v$register
"""
)
}
lithoLinearGradientFingerprint.method.addInstruction(
0,
"invoke-static/range { p4 .. p5 }, $EXTENSION_CLASS_DESCRIPTOR->setLinearGradient([I[F)V"
)
// region apply seekbar custom color to splash screen animation.
// Don't use the lotte splash screen layout if using custom seekbar.
arrayOf(
launchScreenLayoutTypeFingerprint,
mainActivityOnCreateFingerprint
).forEach { fingerprint ->
fingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(launchScreenLayoutTypeLotteFeatureFlag)
val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT) val resultIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(resultIndex).registerA val register = getInstruction<OneRegisterInstruction>(resultIndex).registerA
addInstructions( addInstructions(
resultIndex + 1, resultIndex + 1,
""" """
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->useLotteLaunchSplashScreen(Z)Z
move-result v$register move-result v$register
""", """
) )
} }
}
lithoLinearGradientFingerprint.method.addInstruction( // Hook the splash animation drawable to set the a seekbar color theme.
0, mainActivityOnCreateFingerprint.method.apply {
"invoke-static/range { p4 .. p5 }, $EXTENSION_CLASS_DESCRIPTOR->setLinearGradient([I[F)V", val drawableIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/widget/ImageView;"
&& reference.name == "getDrawable"
}
val checkCastIndex = indexOfFirstInstructionOrThrow(drawableIndex, Opcode.CHECK_CAST)
val drawableRegister = getInstruction<OneRegisterInstruction>(checkCastIndex).registerA
addInstruction(
checkCastIndex + 1,
"invoke-static { v$drawableRegister }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setSplashAnimationDrawableTheme(Landroid/graphics/drawable/AnimatedVectorDrawable;)V"
) )
} }
lithoColorOverrideHook(EXTENSION_CLASS_DESCRIPTOR, "getLithoColor") // endregion
} }
} }

View File

@@ -19,7 +19,6 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ShortsAutoplayPatch;" private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/ShortsAutoplayPatch;"
@Suppress("unused")
val shortsAutoplayPatch = bytecodePatch( val shortsAutoplayPatch = bytecodePatch(
name = "Shorts autoplay", name = "Shorts autoplay",
description = "Adds options to automatically play the next Short.", description = "Adds options to automatically play the next Short.",
@@ -38,6 +37,7 @@ val shortsAutoplayPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )
@@ -56,7 +56,7 @@ val shortsAutoplayPatch = bytecodePatch(
// Main activity is used to check if app is in pip mode. // Main activity is used to check if app is in pip mode.
mainActivityOnCreateFingerprint.method.addInstructions( mainActivityOnCreateFingerprint.method.addInstructions(
0, 1,
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" + "invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
"setMainActivity(Landroid/app/Activity;)V", "setMainActivity(Landroid/app/Activity;)V",
) )

View File

@@ -117,6 +117,7 @@ val sponsorBlockPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )

View File

@@ -8,6 +8,8 @@ import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.ListPreference import app.revanced.patches.shared.misc.settings.preference.ListPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_17_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
@@ -15,16 +17,17 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
private const val EXTENSION_CLASS_DESCRIPTOR = private const val EXTENSION_CLASS_DESCRIPTOR =
"Lapp/revanced/extension/youtube/patches/spoof/SpoofAppVersionPatch;" "Lapp/revanced/extension/youtube/patches/spoof/SpoofAppVersionPatch;"
@Suppress("unused")
val spoofAppVersionPatch = bytecodePatch( val spoofAppVersionPatch = bytecodePatch(
name = "Spoof app version", name = "Spoof app version",
description = "Adds an option to trick YouTube into thinking you are running an older version of the app. " + description = "Adds an option to trick YouTube into thinking you are running an older version of the app. " +
"This can be used to restore old UI elements and features.", "This can be used to restore old UI elements and features. " +
"Patching 19.16.39 or lower includes additional older spoofing targets.",
) { ) {
dependsOn( dependsOn(
sharedExtensionPatch, sharedExtensionPatch,
settingsPatch, settingsPatch,
addResourcesPatch, addResourcesPatch,
versionCheckPatch
) )
compatibleWith( compatibleWith(
@@ -35,6 +38,7 @@ val spoofAppVersionPatch = bytecodePatch(
"19.25.37", "19.25.37",
"19.34.42", "19.34.42",
"19.43.41", "19.43.41",
"19.45.38",
), ),
) )
@@ -43,10 +47,19 @@ val spoofAppVersionPatch = bytecodePatch(
PreferenceScreen.GENERAL_LAYOUT.addPreferences( PreferenceScreen.GENERAL_LAYOUT.addPreferences(
SwitchPreference("revanced_spoof_app_version"), SwitchPreference("revanced_spoof_app_version"),
ListPreference( if (is_19_17_or_greater) {
key = "revanced_spoof_app_version_target", ListPreference(
summaryKey = null, key = "revanced_spoof_app_version_target",
), summaryKey = null,
)
} else {
ListPreference(
key = "revanced_spoof_app_version_target",
summaryKey = null,
entriesKey = "revanced_spoof_app_version_target_legacy_entries",
entryValuesKey = "revanced_spoof_app_version_target_legacy_entry_values"
)
}
) )
val insertIndex = spoofAppVersionFingerprint.patternMatch!!.startIndex + 1 val insertIndex = spoofAppVersionFingerprint.patternMatch!!.startIndex + 1

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