Compare commits

...

25 Commits

Author SHA1 Message Date
semantic-release-bot
c15cc431d6 chore(release): 2.43.0 [skip ci]
# [2.43.0](https://github.com/revanced/revanced-patches/compare/v2.42.1...v2.43.0) (2022-08-26)

### Features

* `client-spoof` patch ([5512c07](fb006f87ab))
2022-08-26 22:07:20 +00:00
epicsampler
fb006f87ab feat: client-spoof patch
Signed-off-by: oSumAtrIX <johan.melkonyan1@web.de>
2022-08-27 00:05:21 +02:00
semantic-release-bot
28206fd804 chore(release): 2.42.1 [skip ci]
## [2.42.1](https://github.com/revanced/revanced-patches/compare/v2.42.0...v2.42.1) (2022-08-26)

### Bug Fixes

* changed default value for autorepeat setting ([#386](https://github.com/revanced/revanced-patches/issues/386)) ([d43add7](e425e75152))
2022-08-26 01:14:13 +00:00
afn
e425e75152 fix: changed default value for autorepeat setting (#386) 2022-08-26 03:11:46 +02:00
Levente Ilyó-Kovács
69d6c55942 docs: punctuation in microg-support patch description (#377) 2022-08-23 00:51:02 +02:00
semantic-release-bot
f2b29351b4 chore(release): 2.42.0 [skip ci]
# [2.42.0](https://github.com/revanced/revanced-patches/compare/v2.41.0...v2.42.0) (2022-08-22)

### Bug Fixes

* default values for settings ([834c4ad](b75e759348))

### Features

* setting for downloader package name ([965d05c](db0b468e71))
* v17.29.34 compatibility for `downloads` patch ([#374](https://github.com/revanced/revanced-patches/issues/374)) ([d81f1af](83b41322c4))
2022-08-22 17:16:38 +00:00
oSumAtrIX
db0b468e71 feat: setting for downloader package name 2022-08-22 19:14:17 +02:00
oSumAtrIX
b75e759348 fix: default values for settings 2022-08-22 19:13:57 +02:00
Robert
83b41322c4 feat: v17.29.34 compatibility for downloads patch (#374) 2022-08-22 14:38:21 +02:00
semantic-release-bot
8d8878aa08 chore(release): 2.41.0 [skip ci]
# [2.41.0](https://github.com/revanced/revanced-patches/compare/v2.40.2...v2.41.0) (2022-08-22)

### Features

* `downloads` patch ([#215](https://github.com/revanced/revanced-patches/issues/215)) ([304fbac](d628674cdd))
2022-08-22 03:00:31 +00:00
oSumAtrIX
d628674cdd feat: downloads patch (#215) 2022-08-22 04:58:17 +02:00
semantic-release-bot
23b182ccbb chore(release): 2.40.2 [skip ci]
## [2.40.2](https://github.com/revanced/revanced-patches/compare/v2.40.1...v2.40.2) (2022-08-22)

### Bug Fixes

* correct title for `tablet-miniplayer` setting switch ([6af6c02](4a784ecd6e))
2022-08-22 02:42:29 +00:00
oSumAtrIX
4a784ecd6e fix: correct title for tablet-miniplayer setting switch 2022-08-22 04:40:49 +02:00
semantic-release-bot
0165b53c6d chore(release): 2.40.1 [skip ci]
## [2.40.1](https://github.com/revanced/revanced-patches/compare/v2.40.0...v2.40.1) (2022-08-22)

### Bug Fixes

* add missing switch for `tablet-mini-player` patch ([244a1b2](17a0e16087))
2022-08-22 02:00:11 +00:00
oSumAtrIX
17a0e16087 fix: add missing switch for tablet-mini-player patch 2022-08-22 03:58:15 +02:00
semantic-release-bot
8cf91f39a5 chore(release): 2.40.0 [skip ci]
# [2.40.0](https://github.com/revanced/revanced-patches/compare/v2.39.1...v2.40.0) (2022-08-22)

### Features

* `settings` patch framework ([#266](https://github.com/revanced/revanced-patches/issues/266)) ([084a99b](9ef93f6618))
2022-08-22 00:02:00 +00:00
oSumAtrIX
9ef93f6618 feat: settings patch framework (#266) 2022-08-22 01:59:43 +02:00
semantic-release-bot
8c3866f5e3 chore(release): 2.39.1 [skip ci]
## [2.39.1](https://github.com/revanced/revanced-patches/compare/v2.39.0...v2.39.1) (2022-08-21)

### Bug Fixes

* make `custom-branding` cross-platform ([#366](https://github.com/revanced/revanced-patches/issues/366)) ([02ac62b](d115d649f4))
2022-08-21 00:35:21 +00:00
Alberto Ponces
d115d649f4 fix: make custom-branding cross-platform (#366) 2022-08-21 02:33:04 +02:00
semantic-release-bot
ddc789395e chore(release): 2.39.0 [skip ci]
# [2.39.0](https://github.com/revanced/revanced-patches/compare/v2.38.0...v2.39.0) (2022-08-19)

### Features

* bundle `dex` file into `jar` file ([#359](https://github.com/revanced/revanced-patches/issues/359)) ([f419252](e1200d4e3f))
2022-08-19 23:29:17 +00:00
Alberto Ponces
e1200d4e3f feat: bundle dex file into jar file (#359) 2022-08-20 01:26:59 +02:00
semantic-release-bot
8276340d2b chore(release): 2.38.0 [skip ci]
# [2.38.0](https://github.com/revanced/revanced-patches/compare/v2.37.0...v2.38.0) (2022-08-17)

### Features

* bump YouTube patches to `v17.32.35` ([#347](https://github.com/revanced/revanced-patches/issues/347)) ([5292a0e](8f32af4de1))
2022-08-17 17:13:42 +00:00
inotia00
8f32af4de1 feat: bump YouTube patches to v17.32.35 (#347) 2022-08-17 19:11:53 +02:00
semantic-release-bot
a2bc9f0722 chore(release): 2.37.0 [skip ci]
# [2.37.0](https://github.com/revanced/revanced-patches/compare/v2.36.2...v2.37.0) (2022-08-15)

### Features

* ˋpflotsh-ecmwf-subscription-unlockˋ patch ([#332](https://github.com/revanced/revanced-patches/issues/332)) ([ae2a1d8](f94bb06996))
2022-08-15 18:56:22 +00:00
Technikte
f94bb06996 feat: ˋpflotsh-ecmwf-subscription-unlockˋ patch (#332) 2022-08-15 20:54:22 +02:00
118 changed files with 1899 additions and 855 deletions

View File

@@ -31,9 +31,6 @@
"assets": [
{
"path": "build/libs/*.jar"
},
{
"path": "build/libs/*.dex"
}
]
}

View File

@@ -1,3 +1,86 @@
# [2.43.0](https://github.com/revanced/revanced-patches/compare/v2.42.1...v2.43.0) (2022-08-26)
### Features
* `client-spoof` patch ([5512c07](https://github.com/revanced/revanced-patches/commit/5512c072fa4b047849dbea0d2d382dd85e3a0827))
## [2.42.1](https://github.com/revanced/revanced-patches/compare/v2.42.0...v2.42.1) (2022-08-26)
### Bug Fixes
* changed default value for autorepeat setting ([#386](https://github.com/revanced/revanced-patches/issues/386)) ([d43add7](https://github.com/revanced/revanced-patches/commit/d43add7c21f0d9f45830476704985755e37d33ef))
# [2.42.0](https://github.com/revanced/revanced-patches/compare/v2.41.0...v2.42.0) (2022-08-22)
### Bug Fixes
* default values for settings ([834c4ad](https://github.com/revanced/revanced-patches/commit/834c4add71570d36b645246621ba24da3869d613))
### Features
* setting for downloader package name ([965d05c](https://github.com/revanced/revanced-patches/commit/965d05cfa55d7a51f64a11f0219e2867568ba852))
* v17.29.34 compatibility for `downloads` patch ([#374](https://github.com/revanced/revanced-patches/issues/374)) ([d81f1af](https://github.com/revanced/revanced-patches/commit/d81f1af327e0d7471f410811af46da34ddfb1bb4))
# [2.41.0](https://github.com/revanced/revanced-patches/compare/v2.40.2...v2.41.0) (2022-08-22)
### Features
* `downloads` patch ([#215](https://github.com/revanced/revanced-patches/issues/215)) ([304fbac](https://github.com/revanced/revanced-patches/commit/304fbacab22538fb0945f564e061783b47120120))
## [2.40.2](https://github.com/revanced/revanced-patches/compare/v2.40.1...v2.40.2) (2022-08-22)
### Bug Fixes
* correct title for `tablet-miniplayer` setting switch ([6af6c02](https://github.com/revanced/revanced-patches/commit/6af6c02154d170153093bd846dfcb7a6205dd6fa))
## [2.40.1](https://github.com/revanced/revanced-patches/compare/v2.40.0...v2.40.1) (2022-08-22)
### Bug Fixes
* add missing switch for `tablet-mini-player` patch ([244a1b2](https://github.com/revanced/revanced-patches/commit/244a1b2cb9f77272dc62287a4a34a487b0289295))
# [2.40.0](https://github.com/revanced/revanced-patches/compare/v2.39.1...v2.40.0) (2022-08-22)
### Features
* `settings` patch framework ([#266](https://github.com/revanced/revanced-patches/issues/266)) ([084a99b](https://github.com/revanced/revanced-patches/commit/084a99bc6f5ed67c0b270e219c2dd75a30f302f1))
## [2.39.1](https://github.com/revanced/revanced-patches/compare/v2.39.0...v2.39.1) (2022-08-21)
### Bug Fixes
* make `custom-branding` cross-platform ([#366](https://github.com/revanced/revanced-patches/issues/366)) ([02ac62b](https://github.com/revanced/revanced-patches/commit/02ac62b0ea7e47ff3aa5078ce4645421f410b154))
# [2.39.0](https://github.com/revanced/revanced-patches/compare/v2.38.0...v2.39.0) (2022-08-19)
### Features
* bundle `dex` file into `jar` file ([#359](https://github.com/revanced/revanced-patches/issues/359)) ([f419252](https://github.com/revanced/revanced-patches/commit/f4192526eab1e3e0208e7460847b892e077fcf5a))
# [2.38.0](https://github.com/revanced/revanced-patches/compare/v2.37.0...v2.38.0) (2022-08-17)
### Features
* bump YouTube patches to `v17.32.35` ([#347](https://github.com/revanced/revanced-patches/issues/347)) ([5292a0e](https://github.com/revanced/revanced-patches/commit/5292a0e973953225f94eed887a5d8f1ead17bb97))
# [2.37.0](https://github.com/revanced/revanced-patches/compare/v2.36.2...v2.37.0) (2022-08-15)
### Features
* ˋpflotsh-ecmwf-subscription-unlockˋ patch ([#332](https://github.com/revanced/revanced-patches/issues/332)) ([ae2a1d8](https://github.com/revanced/revanced-patches/commit/ae2a1d8362e388032c3521101ff60698c4af1583))
## [2.36.2](https://github.com/revanced/revanced-patches/compare/v2.36.1...v2.36.2) (2022-08-14)

View File

@@ -20,6 +20,14 @@ Official patches by ReVanced
| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | all |
</details>
### 📦 `com.garzotto.pflotsh.ecmwf_a`
<details>
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `pflotsh-ecmwf-subscription-unlock` | Unlocks all subscription features. | 3.5.4 |
</details>
### 📦 `com.google.android.apps.youtube.music`
<details>
@@ -58,34 +66,35 @@ Official patches by ReVanced
| 💊 Patch | 📜 Description | 🏹 Target Version |
|:--------:|:--------------:|:-----------------:|
| `swipe-controls` | Adds volume and brightness swipe controls. | 17.29.34 |
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.29.34 |
| `minimized-playback` | Enables minimized and background playback. | 17.29.34 |
| `amoled` | Enables pure black theme. | 17.29.34 |
| `disable-create-button` | Hides the create button in the navigation bar. | 17.29.34 |
| `swipe-controls` | Adds volume and brightness swipe controls. | 17.32.35 |
| `downloads` | Enables downloading music and videos from YouTube. | 17.32.35 |
| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.32.35 |
| `amoled` | Enables pure black theme. | 17.32.35 |
| `disable-create-button` | Hides the create button in the navigation bar. | 17.32.35 |
| `hide-cast-button` | Hides the cast button in the video player. | all |
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 17.29.34 |
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.29.34 |
| `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 17.32.35 |
| `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.32.35 |
| `premium-heading` | Shows premium branding on the home screen. | all |
| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all |
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 17.29.34 |
| `old-quality-layout` | Enables the original quality flyout menu. | 17.29.34 |
| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 17.29.34 |
| `hide-watermark` | Hides creator's watermarks on videos. | 17.29.34 |
| `sponsorblock` | Integrate SponsorBlock. | 17.29.34 |
| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 17.29.34 |
| `tablet-mini-player` | Enables the tablet mini player layout. | 17.29.34 |
| `custom-video-buffer` | Lets you change the buffers of videos. | 17.29.34 |
| `always-autorepeat` | Always repeats the playing video again. | 17.29.34 |
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG | 17.29.34 |
| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 17.32.35 |
| `old-quality-layout` | Enables the original quality flyout menu. | 17.32.35 |
| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 17.32.35 |
| `hide-watermark` | Hides creator's watermarks on videos. | 17.32.35 |
| `sponsorblock` | Integrate SponsorBlock. | 17.32.35 |
| `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 17.32.35 |
| `tablet-mini-player` | Enables the tablet mini player layout. | 17.32.35 |
| `minimized-playback` | Enables minimized and background playback. | 17.32.35 |
| `custom-video-buffer` | Lets you change the buffers of videos. | 17.32.35 |
| `always-autorepeat` | Always repeats the playing video again. | 17.32.35 |
| `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 17.32.35 |
| `settings` | Adds settings for ReVanced to YouTube. | all |
| `enable-debugging` | Enables app debugging by patching the manifest file. | all |
| `custom-playback-speed` | Adds more video playback speed options. | 17.29.34 |
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.29.34 |
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 17.29.34 |
| `video-ads` | Removes ads in the video player. | 17.29.34 |
| `general-ads` | Removes general ads. | 17.29.34 |
| `hide-infocard-suggestions` | Hides infocards in videos. | 17.29.34 |
| `custom-playback-speed` | Adds more video playback speed options. | 17.32.35 |
| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.32.35 |
| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 17.32.35 |
| `video-ads` | Removes ads in the video player. | 17.32.35 |
| `general-ads` | Removes general ads. | 17.32.35 |
| `hide-infocard-suggestions` | Hides infocards in videos. | 17.32.35 |
</details>

View File

@@ -27,15 +27,14 @@ dependencies {
}
tasks {
register<DefaultTask>("generateDex") {
description = "Generate dex files from build"
register<DefaultTask>("generateBundle") {
description = "Generate dex files from build and bundle them in the jar file"
dependsOn(build)
doLast {
val androidHome = System.getenv("ANDROID_HOME") ?: throw GradleException("ANDROID_HOME not found")
val d8 = "${androidHome}/build-tools/32.0.0/d8"
val input = configurations.archives.get().allArtifacts.files.files.first().absolutePath
val output = input.replace(".jar", ".dex")
val work = File("${buildDir}/libs")
exec {
@@ -45,7 +44,7 @@ tasks {
exec {
workingDir = work
commandLine = listOf("mv", "classes.dex", output)
commandLine = listOf("zip", "-u", input, "classes.dex")
}
}
}
@@ -62,6 +61,6 @@ tasks {
register<DefaultTask>("publish") {
group = "publish"
description = "Dummy task"
dependsOn(named("generateDex"), named("generateReadme"))
dependsOn(named("generateBundle"), named("generateReadme"))
}
}

View File

@@ -1,2 +1,2 @@
kotlin.code.style = official
version = 2.36.2
version = 2.43.0

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -23,6 +23,9 @@ import app.revanced.patches.youtube.ad.general.bytecode.extensions.MethodExtensi
import app.revanced.patches.youtube.ad.general.bytecode.utils.MethodUtils.createMutableMethod
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.MutableMethodImplementation
import org.jf.dexlib2.builder.instruction.*
@@ -38,7 +41,7 @@ import org.jf.dexlib2.iface.reference.StringReference
import org.jf.dexlib2.immutable.reference.ImmutableMethodReference
@Patch
@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class])
@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class, SettingsPatch::class])
@Name("general-ads")
@Description("Removes general ads.")
@GeneralAdsCompatibility
@@ -68,6 +71,135 @@ class GeneralBytecodeAdsPatch : BytecodePatch() {
)
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.ADS.addPreferences(
SwitchPreference(
"revanced_home_ads_removal",
StringResource("revanced_home_ads_removal_title", "Remove home ads"),
true,
StringResource("revanced_home_ads_removal_summary_on", "Home ads are hidden"),
StringResource("revanced_home_ads_removal_summary_off", "Home ads are shown")
),
SwitchPreference(
"revanced_adremover_ad_removal",
StringResource("revanced_adremover_ad_removal_enabled_title", "Remove general ads"),
true,
StringResource("revanced_adremover_ad_removal_enabled_summary_on", "General ads are hidden"),
StringResource("revanced_adremover_ad_removal_enabled_summary_off", "General ads are shown")
),
SwitchPreference(
"revanced_adremover_merchandise",
StringResource("revanced_adremover_merchandise_enabled_title", "Remove merchandise banners"),
true,
StringResource("revanced_adremover_merchandise_enabled_summary_on", "Merchandise banners are hidden"),
StringResource("revanced_adremover_merchandise_enabled_summary_off", "Merchandise banners are shown")
),
SwitchPreference(
"revanced_adremover_community_posts_removal",
StringResource("revanced_adremover_community_posts_enabled_title", "Remove community posts"),
true,
StringResource("revanced_adremover_community_posts_enabled_summary_on", "Community posts are hidden"),
StringResource("revanced_adremover_community_posts_enabled_summary_off", "Community posts are shown")
),
SwitchPreference(
"revanced_adremover_compact_banner_removal",
StringResource("revanced_adremover_compact_banner_enabled_title", "Remove compact banners"),
true,
StringResource("revanced_adremover_compact_banner_enabled_summary_on", "Compact banners are hidden"),
StringResource("revanced_adremover_compact_banner_enabled_summary_off", "Compact banners are shown")
),
SwitchPreference(
"revanced_adremover_comments_removal",
StringResource("revanced_adremover_comments_enabled_title", "Remove comments section"),
false,
StringResource("revanced_adremover_comments_enabled_summary_on", "Comment section is hidden"),
StringResource("revanced_adremover_comments_enabled_summary_off", "Comment section is shown")
),
SwitchPreference(
"revanced_adremover_movie",
StringResource("revanced_adremover_movie_enabled_title", "Remove movies section"),
true,
StringResource("revanced_adremover_movie_enabled_summary_on", "Movies section is hidden"),
StringResource("revanced_adremover_movie_enabled_summary_off", "Movies section is shown")
),
SwitchPreference(
"revanced_adremover_feed_survey",
StringResource("revanced_adremover_feed_survey_enabled_title", "Remove feed surveys"),
true,
StringResource("revanced_adremover_feed_survey_enabled_summary_on", "Feed surveys are hidden"),
StringResource("revanced_adremover_feed_survey_enabled_summary_off", "Feed surveys are shown")
),
SwitchPreference(
"revanced_adremover_shorts_shelf",
StringResource("revanced_adremover_shorts_shelf_enabled_title", "Remove shorts shelf"),
true,
StringResource("revanced_adremover_shorts_shelf_enabled_summary_on", "Shorts shelves are hidden"),
StringResource("revanced_adremover_shorts_shelf_enabled_summary_off", "Shorts shelves are shown")
),
SwitchPreference(
"revanced_adremover_community_guidelines",
StringResource("revanced_adremover_community_guidelines_enabled_title", "Remove community guidelines"),
true,
StringResource("revanced_adremover_community_guidelines_enabled_summary_on", "Community guidelines are hidden"),
StringResource("revanced_adremover_community_guidelines_enabled_summary_off", "Community guidelines are shown")
),
SwitchPreference(
"revanced_adremover_emergency_box_removal",
StringResource("revanced_adremover_emergency_box_enabled_title", "Remove emergency boxes"),
true,
StringResource("revanced_adremover_emergency_box_enabled_summary_on", "Emergency boxes are hidden"),
StringResource("revanced_adremover_emergency_box_enabled_summary_off", "Emergency boxes are shown")
),
SwitchPreference(
"revanced_adremover_info_panel",
StringResource("revanced_adremover_info_panel_enabled_title", "Remove info panels"),
true,
StringResource("revanced_adremover_info_panel_enabled_summary_on", "Merchandise banners are hidden"),
StringResource("revanced_adremover_info_panel_enabled_summary_off", "Merchandise banners are shown")
),
SwitchPreference(
"revanced_adremover_medical_panel",
StringResource("revanced_adremover_medical_panel_enabled_title", "Remove medical panels"),
true,
StringResource("revanced_adremover_medical_panel_enabled_summary_on", "Medical panels are hidden"),
StringResource("revanced_adremover_medical_panel_enabled_summary_off", "Medical panels are shown")
),
SwitchPreference(
"revanced_adremover_paid_content",
StringResource("revanced_adremover_paid_content_enabled_title", "Remove paid content"),
true,
StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"),
StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown")
),
SwitchPreference(
"revanced_adremover_suggested",
StringResource("revanced_adremover_suggested_enabled_title", "Remove personal suggestions"),
true,
StringResource("revanced_adremover_suggested_enabled_summary_on", "Personal suggestions are hidden"),
StringResource("revanced_adremover_suggested_enabled_summary_off", "Personal suggestions are shown")
),
SwitchPreference(
"revanced_adremover_hide_suggestions",
StringResource("revanced_adremover_hide_suggestions_enabled_title", "Hide suggestions"),
true,
StringResource("revanced_adremover_hide_suggestions_enabled_summary_on", "Suggestions are hidden"),
StringResource("revanced_adremover_hide_suggestions_enabled_summary_off", "Suggestions are shown")
),
SwitchPreference(
"revanced_adremover_hide_latest_posts",
StringResource("revanced_adremover_hide_latest_posts_enabled_title", "Hide latest posts"),
true,
StringResource("revanced_adremover_hide_latest_posts_enabled_summary_on", "Latest posts are hidden"),
StringResource("revanced_adremover_hide_latest_posts_enabled_summary_off", "Latest posts are shown")
),
SwitchPreference(
"revanced_adremover_hide_channel_guidelines",
StringResource("revanced_adremover_hide_channel_guidelines_enabled_title", "Hide channel guidelines"),
true,
StringResource("revanced_adremover_hide_channel_guidelines_enabled_summary_on", "Channel guidelines are hidden"),
StringResource("revanced_adremover_hide_channel_guidelines_enabled_summary_off", "Channel guidelines are shown")
),
)
// iterating through all classes is expensive
for (classDef in data.classes) {
var mutableClass: MutableClass? = null

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -16,10 +16,13 @@ import app.revanced.patches.youtube.ad.infocardsuggestions.annotations.HideInfoc
import app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints.HideInfocardSuggestionsFingerprint
import app.revanced.patches.youtube.ad.infocardsuggestions.fingerprints.HideInfocardSuggestionsParentFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("hide-infocard-suggestions")
@Description("Hides infocards in videos.")
@HideInfocardSuggestionsCompatibility
@@ -30,6 +33,16 @@ class HideInfocardSuggestionsPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.ADS.addPreferences(
SwitchPreference(
"revanced_info_cards_enabled",
StringResource("revanced_info_cards_enabled_title", "Show info-cards"),
false,
StringResource("revanced_info_cards_enabled_summary_on", "Info-cards are shown"),
StringResource("revanced_info_cards_enabled_summary_off", "Info-cards are hidden")
)
)
val parentResult = HideInfocardSuggestionsParentFingerprint.result
?: return PatchResultError("Parent fingerprint not resolved!")

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -15,9 +15,12 @@ import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility
import app.revanced.patches.youtube.ad.video.fingerprints.ShowVideoAdsConstructorFingerprint
import app.revanced.patches.youtube.ad.video.fingerprints.ShowVideoAdsFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("video-ads")
@Description("Removes ads in the video player.")
@VideoAdsCompatibility
@@ -28,7 +31,19 @@ class VideoAdsPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
ShowVideoAdsFingerprint.resolve(data, ShowVideoAdsConstructorFingerprint.result!!.classDef)
SettingsPatch.PreferenceScreen.ADS.addPreferences(
SwitchPreference(
"revanced_video_ads_removal",
StringResource("revanced_video_ads_removal_title", "Hide video ads"),
true,
StringResource("revanced_video_ads_removal_summary_on", "Video ads are hidden"),
StringResource("revanced_video_ads_removal_summary_off", "Video ads are shown")
)
)
ShowVideoAdsFingerprint.resolve(
data, ShowVideoAdsConstructorFingerprint.result!!.classDef
)
// Override the parameter by calling shouldShowAds and setting the parameter to the result
ShowVideoAdsFingerprint.result!!.mutableMethod.addInstructions(
@@ -40,4 +55,4 @@ class VideoAdsPatch : BytecodePatch(
return PatchResultSuccess()
}
}
}

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.youtube.interaction.downloads.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.27.39", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class DownloadsCompatibility

View File

@@ -0,0 +1,52 @@
package app.revanced.patches.youtube.interaction.downloads.bytecode.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility
import app.revanced.patches.youtube.interaction.downloads.resource.patch.DownloadsResourcePatch
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch
@Patch
@Name("downloads")
@DependsOn([DownloadsResourcePatch::class, PlayerControlsBytecodePatch::class, VideoIdPatch::class])
@Description("Enables downloading music and videos from YouTube.")
@DownloadsCompatibility
@Version("0.0.1")
class DownloadsBytecodePatch : BytecodePatch() {
override fun execute(data: BytecodeData): PatchResult {
val integrationsPackage = "app/revanced/integrations"
val classDescriptor = "L$integrationsPackage/videoplayer/DownloadButton;"
/*
initialize the control
*/
val initializeDownloadsDescriptor = "$classDescriptor->initializeDownloadButton(Ljava/lang/Object;)V"
PlayerControlsBytecodePatch.initializeControl(initializeDownloadsDescriptor)
/*
add code to change the visibility of the control
*/
val changeVisibilityDescriptor = "$classDescriptor->changeVisibility(Z)V"
PlayerControlsBytecodePatch.injectVisibilityCheckCall(changeVisibilityDescriptor)
/*
add code to change to update the video id
*/
val setVideoIdDescriptor =
"L$integrationsPackage/patches/downloads/DownloadsPatch;->setVideoId(Ljava/lang/String;)V"
VideoIdPatch.injectCall(setVideoIdDescriptor)
return PatchResultSuccess()
}
}

View File

@@ -0,0 +1,72 @@
package app.revanced.patches.youtube.interaction.downloads.resource.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import app.revanced.patches.youtube.misc.playercontrols.resource.patch.BottomControlsResourcePatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.*
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.Settings.mergeStrings
import app.revanced.util.resources.ResourceUtils.copyResources
@Name("downloads-resource-patch")
@DependsOn([BottomControlsResourcePatch::class, FixLocaleConfigErrorPatch::class, SettingsPatch::class])
@Description("Makes necessary changes to resources for the download button.")
@DownloadsCompatibility
@Version("0.0.1")
class DownloadsResourcePatch : ResourcePatch() {
override fun execute(data: ResourceData): PatchResult {
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
PreferenceScreen(
"revanced_downloads",
StringResource("revanced_downloads_title", "Download settings"),
listOf(
SwitchPreference(
"revanced_downloads",
StringResource("revanced_downloads_enabled_title", "Show download button"),
true,
StringResource("revanced_downloads_enabled_summary_on", "Download button is visible"),
StringResource("revanced_downloads_enabled_summary_off", "Download button is hidden")
),
TextPreference(
"revanced_downloads_package_name",
StringResource("revanced_downloads_package_name_title", "Downloader package name"),
InputType.STRING,
"org.schabi.newpipe" /* NewPipe */,
StringResource("revanced_downloads_package_name_summary", "Package name of the downloader app such as NewPipe\\'s or PowerTube\\'s")
)
),
StringResource("revanced_downloads_summary", "Settings related to downloads")
)
)
/*
* Copy strings
*/
data.mergeStrings("downloads/host/values/strings.xml")
/*
* Copy resources
*/
data.copyResources("downloads", ResourceUtils.ResourceGroup("drawable", "revanced_yt_download_button.xml"))
/*
* Add download button node
*/
BottomControlsResourcePatch.addControls("downloads/host/layout/${BottomControlsResourcePatch.TARGET_RESOURCE_NAME}")
return PatchResultSuccess()
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -15,6 +15,9 @@ import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappin
import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingFingerprint
import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingParentFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
import org.jf.dexlib2.iface.Method
@@ -22,7 +25,7 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction11n
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("seekbar-tapping")
@Description("Enables tap-to-seek on the seekbar of the video player.")
@SeekbarTappingCompatibility
@@ -33,6 +36,16 @@ class EnableSeekbarTappingPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
SwitchPreference(
"revanced_enable_tap_seeking",
StringResource("revanced_seekbar_tapping_enabled_title", "Enable seekbar tapping"),
true,
StringResource("revanced_seekbar_tapping_summary_on", "Seekbar tapping is enabled"),
StringResource("revanced_seekbar_tapping_summary_off", "Seekbar tapping is disabled")
)
)
var result = SeekbarTappingParentFingerprint.result!!
val tapSeekMethods = mutableMapOf<String, Method>()
@@ -42,7 +55,7 @@ class EnableSeekbarTappingPatch : BytecodePatch(
if (it.implementation == null) continue
val instructions = it.implementation!!.instructions
// here we make sure we actually find the method because it has more then 7 instructions
// here we make sure we actually find the method because it has more than 7 instructions
if (instructions.count() < 7) continue
// we know that the 7th instruction has the opcode CONST_4

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -65,5 +65,4 @@ class SwipeControlsBytecodePatch : BytecodePatch(
}
return PatchResultSuccess()
}
}
}

View File

@@ -1,31 +1,108 @@
package app.revanced.patches.youtube.interaction.swipecontrols.patch.resource
import app.revanced.extensions.injectResources
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.interaction.swipecontrols.annotation.SwipeControlsCompatibility
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.*
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.copyResources
@Name("swipe-controls-resource-patch")
@DependsOn([SettingsPatch::class])
@SwipeControlsCompatibility
@Version("0.0.1")
class SwipeControlsResourcePatch : ResourcePatch() {
override fun execute(data: ResourceData): PatchResult {
SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences(
PreferenceScreen(
"revanced_swipe_controls", StringResource("revanced_swipe_controls_title", "Swipe controls"), listOf(
SwitchPreference(
"revanced_enable_swipe_brightness",
StringResource("revanced_swipe_brightness_enabled_title", "Enable brightness gesture"),
true,
StringResource("revanced_swipe_brightness_summary_on", "Brightness swipe is enabled"),
StringResource("revanced_swipe_brightness_summary_off", "Brightness swipe is disabled")
),
SwitchPreference(
"revanced_enable_swipe_volume",
StringResource("revanced_swipe_volume_enabled_title", "Enable volume gesture"),
true,
StringResource("revanced_swipe_volume_summary_on", "Volume swipe is enabled"),
StringResource("revanced_swipe_volume_summary_off", "Volume swipe is disabled")
),
SwitchPreference(
"revanced_enable_press_to_swipe",
StringResource("revanced_press_to_swipe_enabled_title", "Enable press-to-swipe gesture"),
false,
StringResource("revanced_press_to_swipe_summary_on", "Press-to-swipe is enabled"),
StringResource("revanced_press_to_swipe_summary_off", "Press-to-swipe is disabled")
),
SwitchPreference(
"revanced_enable_swipe_haptic_feedback",
StringResource("revanced_swipe_haptic_feedback_enabled_title", "Enable haptic feedback"),
true,
StringResource("revanced_swipe_haptic_feedback_summary_on", "Haptic feedback is enabled"),
StringResource("revanced_swipe_haptic_feedback_summary_off", "Haptic feedback is disabled")
),
TextPreference(
"revanced_swipe_overlay_timeout",
StringResource("revanced_swipe_overlay_timeout_title", "Swipe overlay timeout"),
InputType.NUMBER,
"500",
StringResource(
"revanced_swipe_overlay_timeout_summary",
"The amount of milliseconds the overlay is visible"
)
),
TextPreference(
"revanced_swipe_overlay_text_size",
StringResource("revanced_swipe_overlay_text_size_title", "Swipe overlay text size"),
InputType.NUMBER,
"22",
StringResource("revanced_swipe_overlay_text_size_summary", "The text size for swipe overlay")
),
TextPreference(
"revanced_swipe_overlay_background_alpha",
StringResource("revanced_swipe_overlay_background_alpha_title", "Swipe background visibility"),
InputType.NUMBER,
"127",
StringResource(
"revanced_swipe_overlay_background_alpha_summary",
"The visibility of swipe overlay background"
)
),
TextPreference(
"revanced_swipe_magnitude_threshold",
StringResource("revanced_swipe_magnitude_threshold_title", "Swipe magnitude threshold"),
InputType.NUMBER,
"30",
StringResource(
"revanced_swipe_magnitude_threshold_summary",
"The amount of threshold for swipe to occur"
)
)
),
StringResource("revanced_swipe_controls_summary","Control volume and brightness")
)
)
val resourcesDir = "swipecontrols"
data.injectResources(
this.javaClass.classLoader,
resourcesDir,
"drawable",
listOf(
"ic_sc_brightness_auto",
"ic_sc_brightness_manual",
"ic_sc_volume_mute",
"ic_sc_volume_normal"
).map { "$it.xml" }
data.copyResources(
"swipecontrols",
ResourceUtils.ResourceGroup(
"drawable",
"ic_sc_brightness_auto.xml",
"ic_sc_brightness_manual.xml",
"ic_sc_volume_mute.xml",
"ic_sc_volume_normal.xml"
)
)
return PatchResultSuccess()
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -14,10 +14,9 @@ import org.jf.dexlib2.Opcode
@MatchingMethod(
"LWillAutonavInformer;", "k"
)
@FuzzyPatternScanMethod(2)
@AutoplayButtonCompatibility
@Version("0.0.1")
object AutonavInformerFingerprint : MethodFingerprint(
object AutoNavInformerFingerprint : MethodFingerprint(
"Z",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null,
@@ -31,4 +30,4 @@ object AutonavInformerFingerprint : MethodFingerprint(
),
null,
{ it.definingClass.endsWith("WillAutonavInformer;") }
)
)

View File

@@ -2,31 +2,19 @@ package app.revanced.patches.youtube.layout.autoplaybutton.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.autoplaybutton.annotations.AutoplayButtonCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@Name("layout-constructor-fingerprint")
@MatchingMethod(
"LYouTubeControlsOverlay;", "F"
)
@FuzzyPatternScanMethod(2)
@AutoplayButtonCompatibility
@Version("0.0.1")
object LayoutConstructorFingerprint : MethodFingerprint(
"V",
AccessFlags.PUBLIC or AccessFlags.FINAL,
null,
listOf(
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
),
listOf("1.0x")
)
null, null, null, null, listOf("1.0x"),
{ methodDef ->
methodDef.definingClass.endsWith("YouTubeControlsOverlay;")
}
)

View File

@@ -1,88 +0,0 @@
package app.revanced.patches.youtube.layout.autoplaybutton.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.layout.autoplaybutton.annotations.AutoplayButtonCompatibility
import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.AutonavInformerFingerprint
import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.LayoutConstructorFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch
@DependsOn([ResourceIdMappingProviderResourcePatch::class, IntegrationsPatch::class])
@Name("hide-autoplay-button")
@Description("Hides the autoplay button in the video player.")
@AutoplayButtonCompatibility
@Version("0.0.1")
class HideAutoplayButton : BytecodePatch(
listOf(
LayoutConstructorFingerprint, AutonavInformerFingerprint
)
) {
override fun execute(data: BytecodeData): PatchResult {
val layoutGenMethod = LayoutConstructorFingerprint.result!!.mutableMethod
val autonavToggle =
ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "autonav_toggle" }
val autonavPreviewStub =
ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "autonav_preview_stub" }
val instructions = layoutGenMethod.implementation!!.instructions
val autonavToggleConstIndex =
instructions.indexOfFirst { (it as? WideLiteralInstruction)?.wideLiteral == autonavToggle.id } + 4
val autonavPreviewStubConstIndex =
instructions.indexOfFirst { (it as? WideLiteralInstruction)?.wideLiteral == autonavPreviewStub.id } + 4
injectIfBranch(layoutGenMethod, autonavToggleConstIndex)
injectIfBranch(layoutGenMethod, autonavPreviewStubConstIndex)
val autonavInformerMethod = AutonavInformerFingerprint.result!!.mutableMethod
//force disable autoplay since it's hard to do without the button
autonavInformerMethod.addInstructions(
0, """
invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z
move-result v0
if-nez v0, :hidden
const/4 v0, 0x0
return v0
:hidden
nop
"""
)
return PatchResultSuccess()
}
private fun injectIfBranch(method: MutableMethod, index: Int) {
val instructions = method.implementation!!.instructions
val insn = (instructions.get(index) as? Instruction35c)!!
val methodToCall = insn.reference.toString()
//remove the invoke-virtual because we want to put it in an if-statement
method.removeInstruction(index)
method.addInstructions(
index, """
invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z
move-result v11
if-eqz v11, :hidebutton
invoke-virtual {v${insn.registerC}, v${insn.registerD}, v${insn.registerE}}, $methodToCall
:hidebutton
nop
"""
)
}
}

View File

@@ -0,0 +1,92 @@
package app.revanced.patches.youtube.layout.autoplaybutton.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.autoplaybutton.annotations.AutoplayButtonCompatibility
import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.AutoNavInformerFingerprint
import app.revanced.patches.youtube.layout.autoplaybutton.fingerprints.LayoutConstructorFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@DependsOn([IntegrationsPatch::class, SettingsPatch::class, ResourceIdMappingProviderResourcePatch::class])
@Name("hide-autoplay-button")
@Description("Hides the autoplay button in the video player.")
@AutoplayButtonCompatibility
@Version("0.0.1")
class HideAutoplayButtonPatch : BytecodePatch(
listOf(
LayoutConstructorFingerprint, AutoNavInformerFingerprint
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_autoplay_button_enabled",
StringResource("revanced_autoplay_button_enabled_title", "Show autoplay button"),
false,
StringResource("revanced_autoplay_button_summary_on", "Autoplay button is shown"),
StringResource("revanced_autoplay_button_summary_off", "Autoplay button is hidden")
)
)
val autoNavInformerMethod = AutoNavInformerFingerprint.result!!.mutableMethod
val layoutGenMethodResult = LayoutConstructorFingerprint.result!!
val layoutGenMethod = layoutGenMethodResult.mutableMethod
val layoutGenMethodInstructions = layoutGenMethod.implementation!!.instructions
// resolve the offsets such as ...
val autoNavPreviewStubId = ResourceIdMappingProviderResourcePatch.resourceMappings.single {
it.name == "autonav_preview_stub"
}.id
// where to insert the branch instructions and ...
val insertIndex = layoutGenMethodInstructions.indexOfFirst {
(it as? WideLiteralInstruction)?.wideLiteral == autoNavPreviewStubId
}
// where to branch away
val branchIndex = layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1).indexOfFirst {
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
} + 2
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction
layoutGenMethod.addInstructions(
insertIndex, """
invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z
move-result v11
if-eqz v11, :hidden
""", listOf(ExternalLabel("hidden", jumpInstruction))
)
//force disable autoplay since it's hard to do without the button
autoNavInformerMethod.addInstructions(
0, """
invoke-static {}, Lapp/revanced/integrations/patches/HideAutoplayButtonPatch;->isButtonShown()Z
move-result v0
if-nez v0, :hidden
const/4 v0, 0x0
return v0
:hidden
nop
"""
)
return PatchResultSuccess()
}
}

View File

@@ -10,6 +10,7 @@ import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.layout.branding.icon.annotations.CustomBrandingCompatibility
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
@@ -45,9 +46,16 @@ class CustomBrandingPatch : ResourcePatch() {
val iconFile = getIconStream("branding/$size/$iconName.png")
?: return PatchResultError("The icon $iconName can not be found.")
val outputStream = ByteArrayOutputStream()
iconFile.use { input ->
outputStream.use { output ->
input.copyTo(output)
}
}
Files.write(
resDirectory.resolve("mipmap-$iconDirectory").resolve("$iconName.png").toPath(),
iconFile.readAllBytes()
outputStream.toByteArray()
)
}
}

View File

@@ -12,15 +12,28 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.castbutton.annotations.CastButtonCompatibility
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("hide-cast-button")
@Description("Hides the cast button in the video player.")
@CastButtonCompatibility
@Version("0.0.1")
class HideCastButtonPatch : BytecodePatch() {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_cast_button_enabled",
StringResource("revanced_cast_button_enabled_title", "Show cast button"),
false,
StringResource("revanced_cast_button_summary_on", "Cast button is shown"),
StringResource("revanced_cast_button_summary_off", "Cast button is hidden")
)
)
data.classes.forEach { classDef ->
classDef.methods.forEach { method ->
if (classDef.type.endsWith("MediaRouteButton;") && method.name == "setVisibility") {

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -50,8 +50,5 @@ object CreateButtonFingerprint : MethodFingerprint(
Opcode.MOVE_OBJECT,
Opcode.MOVE_OBJECT,
Opcode.INVOKE_DIRECT_RANGE,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
)
)

View File

@@ -15,6 +15,9 @@ import app.revanced.patches.youtube.layout.createbutton.annotations.CreateButton
import app.revanced.patches.youtube.layout.createbutton.fingerprints.CreateButtonFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@@ -22,7 +25,7 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@DependsOn([IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class])
@DependsOn([IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class, SettingsPatch::class])
@Name("disable-create-button")
@Description("Hides the create button in the navigation bar.")
@CreateButtonCompatibility
@@ -33,6 +36,16 @@ class CreateButtonRemoverPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_create_button_enabled",
StringResource("revanced_create_button_enabled_title", "Show create button"),
false,
StringResource("revanced_create_button_summary_on", "Create button is shown"),
StringResource("revanced_create_button_summary_off", "Create button is hidden")
)
)
val result = CreateButtonFingerprint.result!!
// Get the required register which holds the view object we need to pass to the method hideCreateButton

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -17,10 +17,13 @@ import app.revanced.patches.youtube.layout.fullscreenpanels.annotations.Fullscre
import app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints.FullscreenViewAdderFingerprint
import app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints.FullscreenViewAdderParentFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
@Patch
@Name("disable-fullscreen-panels")
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Description("Disables video description and comments panel in fullscreen view.")
@FullscreenPanelsCompatibility
@Version("0.0.1")
@@ -30,6 +33,16 @@ class FullscreenPanelsRemoverPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_fullscreen_panels_enabled",
StringResource("revanced_fullscreen_panels_enabled_title", "Show fullscreen panels"),
false,
StringResource("revanced_fullscreen_panels_summary_on", "Fullscreen panels are shown"),
StringResource("revanced_fullscreen_panels_summary_off", "Fullscreen panels are hidden")
)
)
val parentResult = FullscreenViewAdderParentFingerprint.result!!
FullscreenViewAdderFingerprint.resolve(data, parentResult.method, parentResult.classDef)
val result = FullscreenViewAdderParentFingerprint.result

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -13,10 +13,13 @@ import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility
import app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("old-quality-layout")
@Description("Enables the original quality flyout menu.")
@OldQualityLayoutCompatibility
@@ -25,6 +28,16 @@ class OldQualityLayoutPatch : BytecodePatch(
listOf(QualityMenuViewInflateFingerprint)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_use_old_style_quality_settings",
StringResource("revanced_old_style_quality_settings_enabled_title", "Use old quality layout"),
true,
StringResource("revanced_old_style_quality_settings_summary_on", "Old quality settings are shown"),
StringResource("revanced_old_style_quality_settings_summary_off", "New quality settings are shown")
)
)
val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!!
val method = inflateFingerprintResult.mutableMethod
val instructions = method.implementation!!.instructions

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -7,13 +7,18 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility
import app.revanced.patches.youtube.layout.reels.fingerprints.HideReelsFingerprint
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
//@Patch TODO: this is currently in the general-bytecode-ads patch due to the integrations having a preference for including reels or not. Move it here.
@Name("hide-reels")
@Description("Hides reels on the home page.")
@DependsOn([SettingsPatch::class])
@HideReelsCompatibility
@Version("0.0.1")
class HideReelsPatch : BytecodePatch(
@@ -22,6 +27,16 @@ class HideReelsPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_reel_button_enabled",
StringResource("revanced_reel_button_enabled_title", "Show reels button"),
false,
StringResource("revanced_reel_button_summary_on", "Reels button is shown"),
StringResource("revanced_reel_button_summary_off", "Reels button is hidden")
)
)
val result = HideReelsFingerprint.result!!
// HideReel will hide the reel view before it is being used,

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -12,15 +12,16 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentSpecParentFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.DislikeFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.LikeFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.RemoveLikeFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.TextComponentSpecParentFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch
@Patch
@DependsOn([IntegrationsPatch::class, VideoIdPatch::class])
@DependsOn([IntegrationsPatch::class, VideoIdPatch::class, ReturnYouTubeDislikeResourcePatch::class])
@Name("return-youtube-dislike")
@Description("Shows the dislike count of videos using the Return YouTube Dislike API.")
@ReturnYouTubeDislikeCompatibility
@@ -57,9 +58,9 @@ class ReturnYouTubeDislikePatch : BytecodePatch(
val parentResult = TextComponentSpecParentFingerprint.result!!
val createComponentMethod = parentResult.mutableClass.methods.find { method ->
method.parameters.size >= 19 && method.parameterTypes.takeLast(4)
.all { param -> param == "Ljava/util/concurrent/atomic/AtomicReference;" }
}
method.parameters.size >= 19 && method.parameterTypes.takeLast(4)
.all { param -> param == "Ljava/util/concurrent/atomic/AtomicReference;" }
}
?: return PatchResultError("TextComponentSpec.createComponent not found")
val conversionContextParam = 5

View File

@@ -0,0 +1,42 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.util.resources.ResourceUtils.Settings.mergeStrings
@DependsOn([FixLocaleConfigErrorPatch::class, SettingsPatch::class])
@Name("return-youtube-dislike-resource-patch")
@Description("Adds the preferences for Return YouTube Dislike.")
@ReturnYouTubeDislikeCompatibility
@Version("0.0.1")
class ReturnYouTubeDislikeResourcePatch : ResourcePatch() {
override fun execute(data: ResourceData): PatchResult {
val youtubePackage = "com.google.android.youtube"
SettingsPatch.addPreference(
Preference(
StringResource("revanced_ryd_settings_title", "Return YouTube Dislike"),
Preference.Intent(
youtubePackage,
"ryd_settings",
"com.google.android.libraries.social.licenses.LicenseActivity"
),
StringResource("revanced_ryd_settings_summary", "Settings for Return YouTube Dislike"),
)
)
// merge strings
data.mergeStrings("returnyoutubedislike/host/values/strings.xml")
return PatchResultSuccess()
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -22,9 +22,6 @@ object PivotBarButtonTabEnumFingerprint : MethodFingerprint(
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC,
@@ -35,11 +32,5 @@ object PivotBarButtonTabEnumFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC, // SomeEnum.fromValue(tabOrdinal)
Opcode.MOVE_RESULT_OBJECT
)
)

View File

@@ -20,11 +20,6 @@ object PivotBarButtonsViewFingerprint : MethodFingerprint(
AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("Z"),
listOf(
Opcode.INVOKE_VIRTUAL_RANGE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.GOTO,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.IGET,
Opcode.INVOKE_STATIC,

View File

@@ -14,10 +14,14 @@ import app.revanced.patches.youtube.layout.shorts.button.annotations.ShortsButto
import app.revanced.patches.youtube.layout.shorts.button.fingerprints.PivotBarButtonTabEnumFingerprint
import app.revanced.patches.youtube.layout.shorts.button.fingerprints.PivotBarButtonsViewFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.Opcode
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("hide-shorts-button")
@Description("Hides the shorts button on the navigation bar.")
@ShortsButtonCompatibility
@@ -28,27 +32,55 @@ class ShortsButtonRemoverPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_shorts_button_enabled",
StringResource("revanced_shorts_button_enabled_title", "Show shorts button"),
false,
StringResource("revanced_shorts_button_summary_on", "Shorts button is shown"),
StringResource("revanced_shorts_button_summary_off", "Shorts button is hidden")
)
)
val tabEnumResult = PivotBarButtonTabEnumFingerprint.result!!
val tabEnumImplementation = tabEnumResult.mutableMethod.implementation!!
val moveEnumInstruction = tabEnumImplementation.instructions[tabEnumResult.patternScanResult!!.endIndex]
val scanResultEndIndex = tabEnumResult.patternScanResult!!.endIndex
val tabEnumIndex = scanResultEndIndex +
if (tabEnumImplementation.instructions[scanResultEndIndex + 1].opcode == Opcode.IGET_OBJECT) {
// for 17.31.xx and lower
7
} else {
// since 17.32.xx
10
}
val moveEnumInstruction = tabEnumImplementation.instructions[tabEnumIndex]
val enumRegister = (moveEnumInstruction as OneRegisterInstruction).registerA
val buttonsViewResult = PivotBarButtonsViewFingerprint.result!!
val buttonsViewImplementation = buttonsViewResult.mutableMethod.implementation!!
val moveViewInstruction = buttonsViewImplementation.instructions[buttonsViewResult.patternScanResult!!.startIndex + 1]
val scanResultStartIndex = buttonsViewResult.patternScanResult!!.startIndex
val buttonsViewIndex = scanResultStartIndex +
if (buttonsViewImplementation.instructions[scanResultStartIndex - 1].opcode == Opcode.IF_NEZ) {
// for 17.31.xx and lower
-3
} else {
// since 17.32.xx
-6
}
val moveViewInstruction = buttonsViewImplementation.instructions[buttonsViewIndex - 1]
val viewRegister = (moveViewInstruction as OneRegisterInstruction).registerA
// Save the tab enum in XGlobals to avoid smali/register workarounds
tabEnumResult.mutableMethod.addInstruction(
tabEnumResult.patternScanResult!!.endIndex + 1,
tabEnumIndex,
"sput-object v$enumRegister, Lapp/revanced/integrations/patches/HideShortsButtonPatch;->lastPivotTab:Ljava/lang/Enum;"
)
// Hide the button view via proxy by passing it to the hideShortsButton method
// It only hides it if the last tab name is "TAB_SHORTS"
buttonsViewResult.mutableMethod.addInstruction(
buttonsViewResult.patternScanResult!!.startIndex + 3,
buttonsViewIndex + 1,
"invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideShortsButtonPatch;->hideShortsButton(Landroid/view/View;)V"
)

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.22.36", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.22.36", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -1,19 +0,0 @@
package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility
@Name("show-player-controls-fingerprint")
@MatchingMethod(
"LYouTubeControlsOverlay;", "ac"
)
@DirectPatternScanMethod
@SponsorBlockCompatibility
@Version("0.0.1")
object ShowPlayerControlsFingerprint : MethodFingerprint(
"V", null, listOf("Z","Z"), null, null
)

View File

@@ -23,6 +23,7 @@ import app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints.*
import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
import app.revanced.patches.youtube.misc.videoid.patch.VideoIdPatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@@ -38,7 +39,7 @@ import org.jf.dexlib2.util.MethodUtil
@Patch
@DependsOn(
dependencies = [IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class, SponsorBlockResourcePatch::class, VideoIdPatch::class]
dependencies = [PlayerControlsBytecodePatch::class, IntegrationsPatch::class, ResourceIdMappingProviderResourcePatch::class, SponsorBlockResourcePatch::class, VideoIdPatch::class]
)
@Name("sponsorblock")
@Description("Integrate SponsorBlock.")
@@ -147,7 +148,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
it.registerC to it.registerE
}
seekbarMethod.addInstruction(
drawSegmentInstructionInsertIndex - 1,
drawSegmentInstructionInsertIndex,
"invoke-static {v$canvasInstance, v$centerY}, Lapp/revanced/integrations/sponsorblock/PlayerController;->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V"
)
@@ -171,8 +172,7 @@ class SponsorBlockBytecodePatch : BytecodePatch(
/*
Voting & Shield button
*/
ShowPlayerControlsFingerprint.resolve(data, data.classes.find { it.type.endsWith("YouTubeControlsOverlay;") }!!)
val controlsMethodResult = ShowPlayerControlsFingerprint.result!!
val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult
val controlsLayoutStubResourceId =
ResourceIdMappingProviderResourcePatch.resourceMappings.single { it.type == "id" && it.name == "controls_layout_stub" }.id
@@ -217,12 +217,8 @@ class SponsorBlockBytecodePatch : BytecodePatch(
}
// change visibility of the buttons
controlsMethodResult.mutableMethod.addInstructions(
0, """
invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibility(Z)V
invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibility(Z)V
""".trimIndent()
)
PlayerControlsBytecodePatch.injectVisibilityCheckCall("Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibility(Z)V")
PlayerControlsBytecodePatch.injectVisibilityCheckCall("Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibility(Z)V")
// set SegmentHelperLayout.context to the player layout instance
val instanceRegister = 0

View File

@@ -9,96 +9,99 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.Settings.mergeStrings
import app.revanced.util.resources.ResourceUtils.copyResources
import app.revanced.util.resources.ResourceUtils.copyXmlNode
import java.nio.file.Files
@Name("sponsorblock-resource-patch")
@SponsorBlockCompatibility
@DependsOn([FixLocaleConfigErrorPatch::class])
@DependsOn([FixLocaleConfigErrorPatch::class, SettingsPatch::class])
@Version("0.0.1")
class SponsorBlockResourcePatch : ResourcePatch() {
override fun execute(data: ResourceData): PatchResult {
val youtubePackage = "com.google.android.youtube"
SettingsPatch.addPreference(
Preference(
StringResource("sb_settings", "SponsorBlock"),
Preference.Intent(
youtubePackage,
"sponsorblock_settings",
"com.google.android.libraries.social.licenses.LicenseActivity"
),
StringResource("revanced_sponsorblock_settings_summary", "SponsorBlock related settings"),
)
)
val classLoader = this.javaClass.classLoader
/*
merge SponsorBlock strings to main strings
*/
val stringsResourcePath = "values/strings.xml"
val stringsResourceInputStream = classLoader.getResourceAsStream("sponsorblock/$stringsResourcePath")!!
// copy nodes from the resources node to the real resource node
"resources".copyXmlNode(
data.xmlEditor[stringsResourceInputStream],
data.xmlEditor["res/$stringsResourcePath"]
).close() // close afterwards
data.mergeStrings("sponsorblock/host/values/strings.xml")
/*
merge SponsorBlock drawables to main drawables
*/
val drawables = "drawable" to arrayOf(
"ic_sb_adjust",
"ic_sb_compare",
"ic_sb_edit",
"ic_sb_logo",
"ic_sb_publish",
"ic_sb_voting"
)
val layouts = "layout" to arrayOf(
"inline_sponsor_overlay", "new_segment", "skip_sponsor_button"
)
// collect resources
val xmlResources = arrayOf(drawables, layouts)
// write resources
xmlResources.forEach { (path, resourceNames) ->
resourceNames.forEach { name ->
val relativePath = "$path/$name.xml"
Files.copy(
classLoader.getResourceAsStream("sponsorblock/$relativePath")!!,
data["res"].resolve(relativePath).toPath()
)
}
arrayOf(
ResourceUtils.ResourceGroup(
"layout",
"inline_sponsor_overlay.xml",
"new_segment.xml",
"skip_sponsor_button.xml"
),
ResourceUtils.ResourceGroup(
// required resource for back button, because when the base APK is used, this resource will not exist
"drawable",
"ic_sb_adjust.xml",
"ic_sb_compare.xml",
"ic_sb_edit.xml",
"ic_sb_logo.xml",
"ic_sb_publish.xml",
"ic_sb_voting.xml"
),
ResourceUtils.ResourceGroup(
// required resource for back button, because when the base APK is used, this resource will not exist
"drawable-xxxhdpi", "quantum_ic_skip_next_white_24.png"
)
).forEach { resourceGroup ->
data.copyResources("sponsorblock", resourceGroup)
}
/*
merge xml nodes from the host to their real xml files
*/
// collect all host resources
val hostingXmlResources = mapOf("layout" to arrayOf("youtube_controls_layout"))
// copy nodes from host resources to their real xml files
hostingXmlResources.forEach { (path, resources) ->
resources.forEach { resource ->
val hostingResourceStream = classLoader.getResourceAsStream("sponsorblock/host/$path/$resource.xml")!!
val hostingResourceStream =
classLoader.getResourceAsStream("sponsorblock/host/layout/youtube_controls_layout.xml")!!
val targetXmlEditor = data.xmlEditor["res/$path/$resource.xml"]
"RelativeLayout".copyXmlNode(
data.xmlEditor[hostingResourceStream],
targetXmlEditor
).also {
val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes
val targetXmlEditor = data.xmlEditor["res/layout/youtube_controls_layout.xml"]
"RelativeLayout".copyXmlNode(
data.xmlEditor[hostingResourceStream],
targetXmlEditor
).also {
val children = targetXmlEditor.file.getElementsByTagName("RelativeLayout").item(0).childNodes
// Replace the startOf with the voting button view so that the button does not overlap
for (i in 1 until children.length) {
val view = children.item(i)
// Replace the startOf with the voting button view so that the button does not overlap
for (i in 1 until children.length) {
val view = children.item(i)
// Replace the attribute for a specific node only
if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button"))) continue
// Replace the attribute for a specific node only
if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("live_chat_overlay_button"))) continue
// voting button id from the voting button view from the youtube_controls_layout.xml host file
val votingButtonId = "@+id/voting_button"
// voting button id from the voting button view from the youtube_controls_layout.xml host file
val votingButtonId = "@+id/voting_button"
view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId
view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId
break
}
}.close() // close afterwards
break
}
}
}.close() // close afterwards
return PatchResultSuccess()
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.26.35", "17.29.34")
"com.google.android.youtube", arrayOf("17.26.35", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -19,10 +19,13 @@ import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPla
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideNoContextFingerprint
import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("tablet-mini-player")
@Description("Enables the tablet mini player layout.")
@TabletMiniPlayerCompatibility
@@ -34,6 +37,14 @@ class TabletMiniPlayerPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(SwitchPreference(
"revanced_tablet_miniplayer",
StringResource("revanced_tablet_miniplayer_title", "Enable the tablet Mini-player"),
false,
StringResource("revanced_tablet_miniplayer_summary_on", "Tablet Mini-player is enabled"),
StringResource("revanced_tablet_miniplayer_summary_off", "Tablet Mini-player is disabled")
))
// first resolve the fingerprints via the parent fingerprint
val miniPlayerClass = MiniPlayerDimensionsCalculatorFingerprint.result!!.classDef

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -17,9 +17,12 @@ import app.revanced.patches.youtube.layout.watermark.annotations.HideWatermarkCo
import app.revanced.patches.youtube.layout.watermark.fingerprints.HideWatermarkParentFingerprint
import app.revanced.patches.youtube.layout.watermark.fingerprints.HideWatermarkFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("hide-watermark")
@Description("Hides creator's watermarks on videos.")
@HideWatermarkCompatibility
@@ -30,6 +33,16 @@ class HideWatermarkPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_branding_watermark_enabled",
StringResource("revanced_branding_watermark_enabled_title", "Show branding watermark"),
false,
StringResource("revanced_branding_watermark_summary_on", "Branding watermark is shown"),
StringResource("revanced_branding_watermark_summary_off", "Branding watermark is hidden")
)
)
HideWatermarkFingerprint.resolve(data, HideWatermarkParentFingerprint.result!!.classDef)
val result = HideWatermarkFingerprint.result
?: return PatchResultError("Required parent method could not be found.")

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -42,7 +42,7 @@ See:
*/
object WideSearchbarTwoFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L", "L", "L", "L"), listOf(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, null, listOf(
Opcode.INVOKE_STATIC, Opcode.MOVE_RESULT, Opcode.IF_EQZ, Opcode.NEW_INSTANCE
),
null, null

View File

@@ -3,10 +3,8 @@ package app.revanced.patches.youtube.layout.widesearchbar.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.reels.annotations.HideReelsCompatibility
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.widesearchbar.annotations.WideSearchbarCompatibility
import org.jf.dexlib2.AccessFlags
@@ -14,7 +12,6 @@ import org.jf.dexlib2.AccessFlags
@MatchingMethod(
"Lkrf;", "i"
)
@FuzzyPatternScanMethod(3)
@WideSearchbarCompatibility
@Version("0.0.1")

View File

@@ -19,9 +19,12 @@ import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.WideSearch
import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.WideSearchbarTwoFingerprint
import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.WideSearchbarTwoParentFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
@Patch
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@Name("enable-wide-searchbar")
@Description("Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.")
@WideSearchbarCompatibility
@@ -32,6 +35,16 @@ class WideSearchbarPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.LAYOUT.addPreferences(
SwitchPreference(
"revanced_wide_searchbar_enabled",
StringResource("revanced_wide_searchbar_enabled_title", "Enable wide search bar"),
false,
StringResource("revanced_wide_searchbar_summary_on", "Wide search bar is enabled"),
StringResource("revanced_wide_searchbar_summary_off", "Wide search bar is disabled")
)
)
WideSearchbarOneFingerprint.resolve(data, WideSearchbarOneParentFingerprint.result!!.classDef)
WideSearchbarTwoFingerprint.resolve(data, WideSearchbarTwoParentFingerprint.result!!.classDef)

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -17,6 +17,9 @@ import app.revanced.patches.youtube.misc.autorepeat.annotations.AutoRepeatCompat
import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatFingerprint
import app.revanced.patches.youtube.misc.autorepeat.fingerprints.AutoRepeatParentFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
@Patch
@DependsOn([IntegrationsPatch::class])
@@ -30,6 +33,16 @@ class AutoRepeatPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference(
"revanced_pref_auto_repeat",
StringResource("revanced_auto_repeat_enabled_title", "Enable auto-repeat"),
false,
StringResource("revanced_auto_repeat_summary_on", "Auto-repeat is enabled"),
StringResource("revanced_auto_repeat_summary_off", "Auto-repeat is disabled")
)
)
//Get Result from the ParentFingerprint which is the playMethod we need to get.
val parentResult = AutoRepeatParentFingerprint.result
?: return PatchResultError("ParentFingerprint did not resolve.")

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.youtube.misc.clientspoof.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[
Package("com.google.android.youtube", arrayOf()),
Package("com.vanced.android", arrayOf())
]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class ClientSpoofCompatibility

View File

@@ -0,0 +1,20 @@
package app.revanced.patches.youtube.misc.clientspoof.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.clientspoof.annotations.ClientSpoofCompatibility
import org.jf.dexlib2.Opcode
@Name("user-agent-header-builder-fingerprint")
@ClientSpoofCompatibility
@DirectPatternScanMethod
@Version("0.0.1")
object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
null,
null,
listOf("L", "L", "L"),
listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL),
listOf("(Linux; U; Android "),
)

View File

@@ -0,0 +1,38 @@
package app.revanced.patches.youtube.misc.clientspoof.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.misc.clientspoof.annotations.ClientSpoofCompatibility
import app.revanced.patches.youtube.misc.clientspoof.fingerprints.UserAgentHeaderBuilderFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
@Name("client-spoof")
@Description("Spoofs the YouTube or Vanced client to prevent playback issues.")
@DependsOn([IntegrationsPatch::class])
@ClientSpoofCompatibility
@Version("0.0.1")
class ClientSpoofPatch : BytecodePatch(
listOf(UserAgentHeaderBuilderFingerprint)
) {
override fun execute(data: BytecodeData): PatchResult {
val result = UserAgentHeaderBuilderFingerprint.result!!
val method = result.mutableMethod
val insertIndex = result.patternScanResult!!.endIndex
val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD
val originalPackageName = "com.google.android.youtube"
method.addInstructions(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"")
return PatchResultSuccess()
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -35,6 +35,8 @@ class CustomPlaybackSpeedPatch : BytecodePatch(
) {
override fun execute(data: BytecodeData): PatchResult {
//TODO: include setting to skip remembering the new speed
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!!
val arrayGenMethodImpl = arrayGenMethod.implementation!!

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -14,6 +14,9 @@ import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.misc.hdrbrightness.annotations.HDRBrightnessCompatibility
import app.revanced.patches.youtube.misc.hdrbrightness.fingerprints.HDRBrightnessFingerprintXXZ
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
@@ -23,13 +26,23 @@ import org.jf.dexlib2.iface.reference.FieldReference
@Description("Makes the brightness of HDR videos follow the system default.")
@HDRBrightnessCompatibility
@Version("0.0.2")
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
class HDRBrightnessPatch : BytecodePatch(
listOf(
HDRBrightnessFingerprintXXZ
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference(
"revanced_pref_hdr_autobrightness",
StringResource("revanced_hdr_autobrightness_enabled_title", "Enable auto HDR brightness"),
true,
StringResource("revanced_hdr_autobrightness_summary_on", "Auto HDR brightness is enabled"),
StringResource("revanced_hdr_autobrightness_summary_off", "Auto HDR brightness is disabled")
)
)
val method = HDRBrightnessFingerprintXXZ.result?.mutableMethod
?: return PatchResultError("HDRBrightnessFingerprint could not resolve the method!")

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.03.38", "17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.03.38", "17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -28,8 +28,7 @@ class FixLocaleConfigErrorPatch : ResourcePatch() {
// by replacing the attributes name
val attribute = "android:localeConfig"
applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute))
applicationNode.removeAttribute("android:localeConfig")
applicationNode.removeAttribute(attribute)
}
return PatchResultSuccess()

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -14,6 +14,7 @@ import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableClass
import app.revanced.patches.youtube.layout.castbutton.patch.HideCastButtonPatch
import app.revanced.patches.youtube.misc.clientspoof.patch.ClientSpoofPatch
import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility
import app.revanced.patches.youtube.misc.microg.fingerprints.*
import app.revanced.patches.youtube.misc.microg.patch.resource.MicroGResourcePatch
@@ -32,10 +33,11 @@ import org.jf.dexlib2.immutable.reference.ImmutableStringReference
[
MicroGResourcePatch::class,
HideCastButtonPatch::class,
ClientSpoofPatch::class
]
)
@Name("microg-support")
@Description("Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG")
@Description("Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.")
@MicroGPatchCompatibility
@Version("0.0.1")
class MicroGBytecodePatch : BytecodePatch(

View File

@@ -13,6 +13,9 @@ import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibi
import app.revanced.patches.youtube.misc.microg.shared.Constants.BASE_MICROG_PACKAGE_NAME
import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
@Name("microg-resource-patch")
@DependsOn([FixLocaleConfigErrorPatch::class, SettingsResourcePatch::class])
@@ -21,25 +24,14 @@ import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourc
@Version("0.0.1")
class MicroGResourcePatch : ResourcePatch() {
override fun execute(data: ResourceData): PatchResult {
data.xmlEditor["res/xml/settings_fragment.xml"].use {
val settingsElementIntent = it.file.createElement("intent")
settingsElementIntent.setAttribute("android:targetPackage", "$BASE_MICROG_PACKAGE_NAME.android.gms")
settingsElementIntent.setAttribute("android:targetClass", "org.microg.gms.ui.SettingsActivity")
val settingsElement = it.file.createElement("Preference")
settingsElement.setAttribute("android:title", "@string/microg_settings")
settingsElement.appendChild(settingsElementIntent)
it.file.firstChild.appendChild(settingsElement)
}
val settingsFragment = data["res/xml/settings_fragment.xml"]
settingsFragment.writeText(
settingsFragment.readText().replace(
"android:targetPackage=\"com.google.android.youtube",
"android:targetPackage=\"$REVANCED_PACKAGE_NAME"
SettingsPatch.addPreference(
Preference(
StringResource("microg_settings", "MicroG Settings"),
Preference.Intent("$BASE_MICROG_PACKAGE_NAME.android.gms", "", "org.microg.gms.ui.SettingsActivity"),
StringResource("microg_settings_summary", "Settings for MicroG"),
)
)
SettingsPatch.renameIntentsTargetPackage(REVANCED_PACKAGE_NAME)
val manifest = data["AndroidManifest.xml"]
manifest.writeText(

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.youtube.layout.minimizedplayback.annotations
package app.revanced.patches.youtube.misc.minimizedplayback.annotations
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.14.35", "17.17.34", "17.19.36", "17.20.37", "17.22.36", "17.23.35", "17.23.36", "17.24.34", "17.24.35", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -1,11 +1,11 @@
package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode

View File

@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -6,7 +6,7 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode

View File

@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.minimizedplayback.fingerprints
package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
@@ -6,10 +6,9 @@ import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@Name("minimized-playback-manager-fingerprint")
@MatchingMethod(

View File

@@ -1,4 +1,4 @@
package app.revanced.patches.youtube.layout.minimizedplayback.patch
package app.revanced.patches.youtube.misc.minimizedplayback.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
@@ -12,11 +12,14 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackKidsFingerprint
import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
import app.revanced.patches.youtube.layout.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.annotations.MinimizedPlaybackCompatibility
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackKidsFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint
import app.revanced.patches.youtube.misc.minimizedplayback.fingerprints.MinimizedPlaybackSettingsFingerprint
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.SwitchPreference
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference
@@ -24,7 +27,7 @@ import org.jf.dexlib2.iface.reference.MethodReference
@Patch
@Name("minimized-playback")
@Description("Enables minimized and background playback.")
@DependsOn([IntegrationsPatch::class])
@DependsOn([IntegrationsPatch::class, SettingsPatch::class])
@MinimizedPlaybackCompatibility
@Version("0.0.1")
class MinimizedPlaybackPatch : BytecodePatch(
@@ -33,6 +36,16 @@ class MinimizedPlaybackPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
SwitchPreference(
"revanced_enable_minimized_playback",
StringResource("revanced_minimized_playback_enabled_title", "Enable minimized playback"),
true,
StringResource("revanced_minimized_playback_summary_on", "Minimized playback is enabled"),
StringResource("revanced_minimized_playback_summary_off", "Minimized playback is disabled")
)
)
// Instead of removing all instructions like Vanced,
// we return the method at the beginning instead
MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions(

View File

@@ -0,0 +1,13 @@
package app.revanced.patches.youtube.misc.playercontrols.annotation
import app.revanced.patcher.annotation.Compatibility
import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.27.39", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
internal annotation class PlayerControlsCompatibility

View File

@@ -0,0 +1,83 @@
package app.revanced.patches.youtube.misc.playercontrols.bytecode.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.fingerprint.method.utils.MethodFingerprintUtils.resolve
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.BottomControlsInflateFingerprint
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.PlayerControlsVisibilityFingerprint
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("player-controls-bytecode-patch")
@DependsOn([ResourceIdMappingProviderResourcePatch::class])
@Description("Manages the code for the player controls of the YouTube player.")
@PlayerControlsCompatibility
@Version("0.0.1")
class PlayerControlsBytecodePatch : BytecodePatch(
listOf(PlayerControlsVisibilityFingerprint)
) {
override fun execute(data: BytecodeData): PatchResult {
showPlayerControlsFingerprintResult = PlayerControlsVisibilityFingerprint.result!!
bottomUiContainerResourceId = ResourceIdMappingProviderResourcePatch
.resourceMappings
.single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id
// TODO: another solution is required, this is hacky
listOf(BottomControlsInflateFingerprint).resolve(data, data.classes)
inflateFingerprintResult = BottomControlsInflateFingerprint.result!!
return PatchResultSuccess()
}
internal companion object {
var bottomUiContainerResourceId: Long = 0
lateinit var showPlayerControlsFingerprintResult: MethodFingerprintResult
private var inflateFingerprintResult: MethodFingerprintResult? = null
set(fingerprint) {
field = fingerprint!!.also {
moveToRegisterInstructionIndex = it.patternScanResult!!.endIndex
viewRegister =
(it.mutableMethod.implementation!!.instructions[moveToRegisterInstructionIndex] as OneRegisterInstruction).registerA
}
}
private var moveToRegisterInstructionIndex: Int = 0
private var viewRegister: Int = 0
/**
* Injects the code to change the visibility of controls.
* @param descriptor The descriptor of the method which should be called.
*/
fun injectVisibilityCheckCall(descriptor: String) {
showPlayerControlsFingerprintResult.mutableMethod.addInstruction(
0,
"""
invoke-static {p1}, $descriptor
"""
)
}
/**
* Injects the code to initialize the controls.
* @param descriptor The descriptor of the method which should be calleed.
*/
fun initializeControl(descriptor: String) {
inflateFingerprintResult!!.mutableMethod.addInstruction(
moveToRegisterInstructionIndex + 1,
"invoke-static {v$viewRegister}, $descriptor"
)
}
}
}

View File

@@ -0,0 +1,31 @@
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@Name("bottom-controls-inflate-fingerprint")
@MatchingMethod(
"Lknf;", "a"
)
@DirectPatternScanMethod
@PlayerControlsCompatibility
@Version("0.0.1")
object BottomControlsInflateFingerprint : MethodFingerprint(
null, null, null, listOf(
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT
), null,
{ methodDef ->
methodDef.implementation?.instructions?.any { instruction ->
(instruction as? WideLiteralInstruction)?.wideLiteral == PlayerControlsBytecodePatch.bottomUiContainerResourceId
} == true
}
)

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.youtube.misc.playercontrols.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.DirectPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
@Name("player-controls-visibility-fingerprint")
@MatchingMethod(
"LYouTubeControlsOverlay;", "ag"
)
@DirectPatternScanMethod
@PlayerControlsCompatibility
@Version("0.0.1")
object PlayerControlsVisibilityFingerprint : MethodFingerprint(
"V", null, listOf("Z", "Z"), null, null, { methodDef ->
methodDef.definingClass.endsWith("YouTubeControlsOverlay;")
}
)

View File

@@ -0,0 +1,86 @@
package app.revanced.patches.youtube.misc.playercontrols.resource.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.DomFileEditor
import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility
import java.io.Closeable
@Name("bottom-controls-resource-patch")
@DependsOn([FixLocaleConfigErrorPatch::class])
@Description("Manages the resources for the bottom controls of the YouTube player.")
@PlayerControlsCompatibility
@Version("0.0.1")
class BottomControlsResourcePatch : ResourcePatch(), Closeable {
override fun execute(data: ResourceData): PatchResult {
resourceData = data
targetXmlEditor = data.xmlEditor[TARGET_RESOURCE]
return PatchResultSuccess()
}
companion object {
internal const val TARGET_RESOURCE_NAME = "youtube_controls_bottom_ui_container.xml"
private const val TARGET_RESOURCE = "res/layout/$TARGET_RESOURCE_NAME"
private lateinit var resourceData: ResourceData
private lateinit var targetXmlEditor: DomFileEditor
// The element to which to add the new elements to
private var lastLeftOf = "fullscreen_button"
/**
* Add new controls to the bottom of the YouTube player.
* @param hostYouTubeControlsBottomUiResourceName The hosting resource name containing the elements.
*/
internal fun addControls(hostYouTubeControlsBottomUiResourceName: String) {
val sourceXmlEditor =
resourceData.xmlEditor[this::class.java.classLoader.getResourceAsStream(
hostYouTubeControlsBottomUiResourceName
)!!]
val targetElement =
"android.support.constraint.ConstraintLayout"
val hostElements = sourceXmlEditor.file.getElementsByTagName(targetElement).item(0).childNodes
val destinationResourceFile = this.targetXmlEditor.file
val destinationElement =
destinationResourceFile.getElementsByTagName(targetElement).item(0)
for (index in 1 until hostElements.length) {
val element = hostElements.item(index).cloneNode(true)
// if the element has no attributes theres no point to adding it to the destination
if (!element.hasAttributes()) continue
// set the elements lastLeftOf attribute to the lastLeftOf value
val namespace = "@+id"
element.attributes.getNamedItem("yt:layout_constraintRight_toLeftOf").nodeValue =
"$namespace/$lastLeftOf"
// set lastLeftOf attribute to the the current element
val nameSpaceLength = 4
lastLeftOf = element.attributes.getNamedItem("android:id").nodeValue.substring(nameSpaceLength)
// copy the element
destinationResourceFile.adoptNode(element)
destinationElement.appendChild(element)
}
sourceXmlEditor.close()
}
}
override fun close() {
targetXmlEditor.close()
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.24.34", "17.25.34", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.22.36", "17.24.35", "17.26.35", "17.27.39", "17.28.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.22.36", "17.24.35", "17.26.35", "17.27.39", "17.28.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -33,6 +33,8 @@ class RememberVideoQualityPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
//TODO: include setting to skip remembering the new quality
val setterMethod = VideoQualitySetterFingerprint.result!!
VideoUserQualityChangeFingerprint.resolve(data, setterMethod.classDef)

View File

@@ -4,7 +4,7 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility
import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility
// TODO: This is more of a class fingerprint than a method fingerprint.
// Convert to a class fingerprint whenever possible.
@@ -12,7 +12,7 @@ import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.Retu
@MatchingMethod(
"Lcom/google/android/libraries/social/licenses/LicenseActivity;", "onCreate"
)
@ReturnYouTubeDislikeCompatibility
@SettingsCompatibility
@Version("0.0.1")
object LicenseActivityFingerprint : MethodFingerprint(
null,

View File

@@ -2,10 +2,9 @@ package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility
import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility
// TODO: This is more of a class fingerprint than a method fingerprint.
// Convert to a class fingerprint whenever possible.
@@ -13,7 +12,7 @@ import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.Retu
@MatchingMethod(
"Lapp/revanced/integrations/settingsmenu/ReVancedSettingActivity;", "initializeSettings"
)
@ReturnYouTubeDislikeCompatibility
@SettingsCompatibility
@Version("0.0.1")
object ReVancedSettingsActivityFingerprint : MethodFingerprint(
null,

View File

@@ -4,7 +4,7 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility
import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@@ -13,7 +13,7 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@MatchingMethod(
"Lfyq;", "a"
)
@ReturnYouTubeDislikeCompatibility
@SettingsCompatibility
@Version("0.0.1")
object ThemeSetterFingerprint : MethodFingerprint(
"L",

View File

@@ -18,14 +18,20 @@ import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibil
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ReVancedSettingsActivityFingerprint
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterFingerprint
import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference
import app.revanced.patches.youtube.misc.settings.framework.components.impl.ArrayResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.Preference
import app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch
import org.jf.dexlib2.util.MethodUtil
import java.io.Closeable
@Patch
@DependsOn(
[
IntegrationsPatch::class,
SettingsResourcePatch::class,
ResourceIdMappingProviderResourcePatch::class
]
)
@Name("settings")
@@ -34,7 +40,7 @@ import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourc
@Version("0.0.1")
class SettingsPatch : BytecodePatch(
listOf(LicenseActivityFingerprint, ReVancedSettingsActivityFingerprint, ThemeSetterFingerprint)
) {
), Closeable {
override fun execute(data: BytecodeData): PatchResult {
val licenseActivityResult = LicenseActivityFingerprint.result!!
val settingsResult = ReVancedSettingsActivityFingerprint.result!!
@@ -65,7 +71,7 @@ class SettingsPatch : BytecodePatch(
)
}
// add the setTheme call to the onCreate method to not affect the offsets.
// add the setTheme call to the onCreate method to not affect the offsets
onCreate.addInstructions(
1,
"""
@@ -74,18 +80,76 @@ class SettingsPatch : BytecodePatch(
"""
)
// add the initializeSettings call to the onCreate method.
// add the initializeSettings call to the onCreate method
onCreate.addInstruction(
0,
"invoke-static { p0 }, ${settingsClass.type}->$setThemeMethodName(${licenseActivityClass.type})V"
)
// get rid of, now, useless overridden methods
licenseActivityResult.mutableClass.methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) }
return PatchResultSuccess()
}
internal companion object {
val appearanceStringId = ResourceIdMappingProviderResourcePatch.resourceMappings.find {
// TODO: hide this somehow
var appearanceStringId: Long = ResourceIdMappingProviderResourcePatch.resourceMappings.find {
it.type == "string" && it.name == "app_theme_appearance_dark"
}!!.id
fun addString(identifier: String, value: String, formatted: Boolean = true) =
SettingsResourcePatch.addString(identifier, value, formatted)
fun addPreferenceScreen(preferenceScreen: app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen) =
SettingsResourcePatch.addPreferenceScreen(preferenceScreen)
fun addPreference(preference: Preference) =
SettingsResourcePatch.addPreference(preference)
fun addArray(arrayResource: ArrayResource) =
SettingsResourcePatch.addArray(arrayResource)
fun renameIntentsTargetPackage(newPackage: String) {
SettingsResourcePatch.overrideIntentsTargetPackage = newPackage
}
}
/**
* Preference screens patches should add their settings to.
*/
internal enum class PreferenceScreen(
private val key: String,
private val title: String,
private val summary: String? = null,
private val preferences: MutableList<BasePreference> = mutableListOf()
) : Closeable {
ADS("ads", "Ads", "Ad related settings"),
INTERACTIONS("interactions", "Interaction", "Settings related to interactions"),
LAYOUT("layout", "Layout", "Settings related to the layout"),
MISC("misc", "Miscellaneous", "Miscellaneous patches");
override fun close() {
if (preferences.size == 0) return
addPreferenceScreen(
PreferenceScreen(
key,
StringResource("${key}_title", title),
preferences,
summary?.let { summary ->
StringResource("${key}_summary", summary)
}
)
)
}
/**
* Add preferences to the preference screen.
*/
fun addPreferences(vararg preferences: BasePreference) = this.preferences.addAll(preferences)
}
override fun close() = PreferenceScreen.values().forEach(PreferenceScreen::close)
}

View File

@@ -0,0 +1,14 @@
package app.revanced.patches.youtube.misc.settings.framework.components
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
/**
* Base preference class for all preferences.
*
* @param key The key of the preference.
* @param title The title of the preference.
*/
internal abstract class BasePreference(
override val key: String,
override val title: StringResource,
) : IPreference

View File

@@ -0,0 +1,23 @@
package app.revanced.patches.youtube.misc.settings.framework.components
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
/**
* Preference
*/
internal interface IPreference {
/**
* Key of the preference.
*/
val key: String
/**
* Title of the preference.
*/
val title: StringResource
/**
* Tag name of the preference.
*/
val tag: String
}

View File

@@ -0,0 +1,9 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
/**
* Represents an array resource.
*
* @param name The name of the array resource.
* @param items The items of the array resource.
*/
internal data class ArrayResource(val name: String, val items: List<StringResource>)

View File

@@ -0,0 +1,6 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
enum class InputType(val type: String) {
STRING("text"),
NUMBER("number"),
}

View File

@@ -0,0 +1,18 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
/**
* A Preference object.
*
* @param title The title of the preference.
* @param intent The intent of the preference.
* @param summary The summary of the text preference.
*/
internal class Preference(
val title: StringResource,
val intent: Intent,
val summary: StringResource? = null
) {
val tag: String = "Preference"
data class Intent(val targetPackage: String, val data: String, val targetClass: String)
}

View File

@@ -0,0 +1,20 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference
/**
* Preference screen.
*
* @param key The key of the preference.
* @param title The title of the preference.
* @param preferences Child preferences of this screen.
* @param summary The summary of the text preference.
*/
internal open class PreferenceScreen(
key: String,
title: StringResource,
val preferences: List<BasePreference>,
var summary: StringResource? = null
) : BasePreference(key, title) {
override val tag: String = "PreferenceScreen"
}

View File

@@ -0,0 +1,10 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
/**
* Represents a string value in the strings.xml file
*
* @param name The name of the string
* @param value The value of the string
* @param formatted If the string is formatted. If false, the attribute will be set
*/
internal data class StringResource(val name: String, val value: String, val formatted: Boolean = true)

View File

@@ -0,0 +1,21 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference
/**
* Switch preference.
*
* @param key The key of the switch.
* @param title The title of the switch.
* @param default The default value of the switch.
* @param summaryOn The summary to show when the preference is enabled.
* @param summaryOff The summary to show when the preference is disabled.
*/
internal class SwitchPreference(
key: String, title: StringResource,
val default: Boolean = false,
var summaryOn: StringResource? = null,
var summaryOff: StringResource? = null
) : BasePreference(key, title) {
override val tag: String = "SwitchPreference"
}

View File

@@ -0,0 +1,22 @@
package app.revanced.patches.youtube.misc.settings.framework.components.impl
import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference
/**
* Text preference.
*
* @param key The key of the text preference.
* @param title The title of the text preference.
* @param inputType The input type of the text preference.
* @param default The default value of the text preference.
* @param summary The summary of the text preference.
*/
internal class TextPreference(
key: String,
title: StringResource,
var inputType: InputType = InputType.STRING,
var default: String? = null,
var summary: StringResource? = null
) : BasePreference(key, title) {
override val tag: String = "EditTextPreference"
}

View File

@@ -2,71 +2,290 @@ package app.revanced.patches.youtube.misc.settings.resource.patch
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.impl.DomFileEditor
import app.revanced.patcher.data.impl.ResourceData
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.impl.ResourcePatch
import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch
import app.revanced.patches.youtube.misc.mapping.patch.ResourceIdMappingProviderResourcePatch
import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.BasePreference
import app.revanced.patches.youtube.misc.settings.framework.components.impl.*
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.copyResources
import app.revanced.util.resources.ResourceUtils.copyXmlNode
import org.w3c.dom.Element
import org.w3c.dom.Node
import java.io.Closeable
@Name("settings-resource-patch")
@SettingsCompatibility
@DependsOn([FixLocaleConfigErrorPatch::class])
@DependsOn([FixLocaleConfigErrorPatch::class, ResourceIdMappingProviderResourcePatch::class])
@Version("0.0.1")
class SettingsResourcePatch : ResourcePatch() {
class SettingsResourcePatch : ResourcePatch(), Closeable {
override fun execute(data: ResourceData): PatchResult {
/*
* Copy strings
* create missing directory for the resources
*/
data.copyXmlNode("settings/host", "values/strings.xml", "resources")
data["res/drawable-ldrtl-xxxhdpi"].mkdirs()
/*
* Copy arrays
*/
data.copyXmlNode("settings/host", "values/arrays.xml", "resources")
/*
* Copy preference fragments
*/
data.copyXmlNode("settings/host", "xml/settings_fragment.xml", "PreferenceScreen")
/*
* Copy layout resources
* copy layout resources
*/
arrayOf(
ResourceUtils.ResourceGroup(
"layout",
"xsettings_toolbar.xml",
"xsettings_with_toolbar.xml",
"xsettings_with_toolbar_layout.xml"
),
ResourceUtils.ResourceGroup(
"xml",
"revanced_prefs.xml"
"revanced_settings_toolbar.xml",
"revanced_settings_with_toolbar.xml",
"revanced_settings_with_toolbar_layout.xml"
), ResourceUtils.ResourceGroup(
"xml", "revanced_prefs.xml" // template for new preferences
), ResourceUtils.ResourceGroup(
// required resource for back button, because when the base APK is used, this resource will not exist
"drawable-xxxhdpi", "quantum_ic_arrow_back_white_24.png"
), ResourceUtils.ResourceGroup(
// required resource for back button, because when the base APK is used, this resource will not exist
"drawable-ldrtl-xxxhdpi", "quantum_ic_arrow_back_white_24.png"
)
).forEach { resourceGroup ->
data.copyResources("settings", resourceGroup)
}
data.xmlEditor["AndroidManifest.xml"].use {
val manifestNode = it
.file
.getElementsByTagName("manifest")
.item(0) as Element
val element = it.file.createElement("uses-permission")
element.setAttribute("android:name", "android.permission.SCHEDULE_EXACT_ALARM")
manifestNode.appendChild(element)
data.xmlEditor["AndroidManifest.xml"].use { editor ->
editor.file.getElementsByTagName("manifest").item(0).also {
it.appendChild(it.ownerDocument.createElement("uses-permission").also { element ->
element.setAttribute("android:name", "android.permission.SCHEDULE_EXACT_ALARM")
})
}
}
revancedPreferencesEditor = data.xmlEditor["res/xml/revanced_prefs.xml"]
preferencesEditor = data.xmlEditor["res/xml/settings_fragment.xml"]
stringsEditor = data.xmlEditor["res/values/strings.xml"]
arraysEditor = data.xmlEditor["res/values/arrays.xml"]
// Add the ReVanced settings to the YouTube settings
val youtubePackage = "com.google.android.youtube"
SettingsPatch.addPreference(
Preference(
StringResource("revanced_settings", "ReVanced"),
Preference.Intent(
youtubePackage, "revanced_settings", "com.google.android.libraries.social.licenses.LicenseActivity"
),
StringResource("revanced_settings_summary", "ReVanced specific settings"),
)
)
return PatchResultSuccess()
}
internal companion object {
// if this is not null, all intents will be renamed to this
var overrideIntentsTargetPackage: String? = null
private var revancedPreferenceNode: Node? = null
private var preferencesNode: Node? = null
private var stringsNode: Node? = null
private var arraysNode: Node? = null
private var strings = mutableListOf<StringResource>()
private var revancedPreferencesEditor: DomFileEditor? = null
set(value) {
field = value
revancedPreferenceNode = value.getNode("PreferenceScreen")
}
private var preferencesEditor: DomFileEditor? = null
set(value) {
field = value
preferencesNode = value.getNode("PreferenceScreen")
}
private var stringsEditor: DomFileEditor? = null
set(value) {
field = value
stringsNode = value.getNode("resources")
}
private var arraysEditor: DomFileEditor? = null
set(value) {
field = value
arraysNode = value.getNode("resources")
}
/**
* Add a new string to the resources.
*
* @param identifier The key of the string.
* @param value The value of the string.
* @throws IllegalArgumentException if the string already exists.
*/
fun addString(identifier: String, value: String, formatted: Boolean) =
StringResource(identifier, value, formatted).include()
/**
* Add an array to the resources.
*
* @param arrayResource The array resource to add.
*/
fun addArray(arrayResource: ArrayResource) {
arraysNode!!.appendChild(arraysNode!!.ownerDocument.createElement("string-array").also { arrayNode ->
arrayResource.items.forEach { item ->
item.include()
arrayNode.setAttribute("name", item.name)
arrayNode.appendChild(arrayNode.ownerDocument.createElement("item").also { itemNode ->
itemNode.textContent = item.value
})
}
})
}
/**
* Add a preference screen to the settings.
*
* @param preferenceScreen The name of the preference screen.
*/
fun addPreferenceScreen(preferenceScreen: PreferenceScreen) =
revancedPreferenceNode!!.addPreference(preferenceScreen)
/**
* Add a preference fragment to the preferences.
*
* @param preference The preference to add.
*/
fun addPreference(preference: Preference) {
preferencesNode!!.appendChild(preferencesNode.createElement(preference.tag).also { preferenceNode ->
preferenceNode.setAttribute(
"android:title", "@string/${preference.title.also { it.include() }.name}"
)
preference.summary?.let { summary ->
preferenceNode.setAttribute("android:summary", "@string/${summary.also { it.include() }.name}")
}
preferenceNode.appendChild(preferenceNode.createElement("intent").also { intentNode ->
intentNode.setAttribute("android:targetPackage", preference.intent.targetPackage)
intentNode.setAttribute("android:data", preference.intent.data)
intentNode.setAttribute("android:targetClass", preference.intent.targetClass)
})
})
}
/**
* Add a preference to the settings.
*
* @param preference The preference to add.
*/
private fun Node.addPreference(preference: BasePreference) {
// add a summary to the element
fun Element.addSummary(summaryResource: StringResource?, summaryType: SummaryType = SummaryType.DEFAULT) =
summaryResource?.let { summary ->
setAttribute("android:${summaryType.type}", "@string/${summary.also { it.include() }.name}")
}
fun <T> Element.addDefault(default: T) {
default?.let {
setAttribute(
"android:defaultValue", when (it) {
is Boolean -> if (it) "true" else "false"
is String -> it
else -> throw IllegalArgumentException("Unsupported default value type: ${it::class.java.name}")
}
)
}
}
val preferenceElement = ownerDocument.createElement(preference.tag)
preferenceElement.setAttribute("android:key", preference.key)
preferenceElement.setAttribute("android:title", "@string/${preference.title.also { it.include() }.name}")
when (preference) {
is PreferenceScreen -> {
for (childPreference in preference.preferences) preferenceElement.addPreference(childPreference)
preferenceElement.addSummary(preference.summary)
}
is SwitchPreference -> {
preferenceElement.addDefault(preference.default)
preferenceElement.addSummary(preference.summaryOn, SummaryType.ON)
preferenceElement.addSummary(preference.summaryOff, SummaryType.OFF)
}
is TextPreference -> {
preferenceElement.setAttribute("android:inputType", preference.inputType.type)
preferenceElement.addDefault(preference.default)
preferenceElement.addSummary(preference.summary)
}
}
appendChild(preferenceElement)
}
/**
* Add a new string to the resources.
*
* @throws IllegalArgumentException if the string already exists.
*/
private fun StringResource.include() {
if (strings.any { it.name == name }) return
strings.add(this)
}
private fun DomFileEditor?.getNode(tagName: String) = this!!.file.getElementsByTagName(tagName).item(0)
private fun Node?.createElement(tagName: String) = this!!.ownerDocument.createElement(tagName)
private enum class SummaryType(val type: String) {
DEFAULT("summary"), ON("summaryOn"), OFF("summaryOff")
}
}
override fun close() {
// merge all strings, skip duplicates
strings.forEach { stringResource ->
stringsNode!!.appendChild(stringsNode!!.ownerDocument.createElement("string").also { stringElement ->
stringElement.setAttribute("name", stringResource.name)
// if the string is un-formatted, explicitly add the formatted attribute
if (!stringResource.formatted) stringElement.setAttribute("formatted", "false")
stringElement.textContent = stringResource.value
})
}
// rename the intent package names if it was set
overrideIntentsTargetPackage?.let { packageName ->
val preferences = preferencesEditor!!.getNode("PreferenceScreen").childNodes
for (i in 1 until preferences.length) {
val preferenceNode = preferences.item(i)
// preferences have a child node with the intent tag, skip over every other node
if (preferenceNode.childNodes.length == 0) continue
val intentNode = preferenceNode.firstChild
// if the node doesn't have a target package attribute, skip it
val targetPackageAttribute = intentNode.attributes.getNamedItem("android:targetPackage") ?: continue
// do not replace intent target package if the package name is not from YouTube
val youtubePackage = "com.google.android.youtube"
if (targetPackageAttribute.nodeValue != youtubePackage) continue
// replace the target package name
intentNode.attributes.setNamedItem(preferenceNode.ownerDocument.createAttribute("android:targetPackage")
.also { attribute ->
attribute.value = packageName
})
}
}
revancedPreferencesEditor?.close()
preferencesEditor?.close()
stringsEditor?.close()
arraysEditor?.close()
}
}

View File

@@ -5,7 +5,7 @@ import app.revanced.patcher.annotation.Package
@Compatibility(
[Package(
"com.google.android.youtube", arrayOf("17.25.34", "17.29.34")
"com.google.android.youtube", arrayOf("17.25.34", "17.29.34", "17.32.35")
)]
)
@Target(AnnotationTarget.CLASS)

View File

@@ -7,8 +7,14 @@ import app.revanced.patcher.data.impl.BytecodeData
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.patch.impl.BytecodePatch
import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch
import app.revanced.patches.youtube.misc.settings.framework.components.impl.InputType
import app.revanced.patches.youtube.misc.settings.framework.components.impl.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.framework.components.impl.StringResource
import app.revanced.patches.youtube.misc.settings.framework.components.impl.TextPreference
import app.revanced.patches.youtube.misc.videobuffer.annotations.CustomVideoBufferCompatibility
import app.revanced.patches.youtube.misc.videobuffer.fingerprints.MaxBufferFingerprint
import app.revanced.patches.youtube.misc.videobuffer.fingerprints.PlaybackBufferFingerprint
@@ -18,6 +24,7 @@ import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("custom-video-buffer")
@Description("Lets you change the buffers of videos.")
@DependsOn([SettingsPatch::class])
@CustomVideoBufferCompatibility
@Version("0.0.1")
class CustomVideoBufferPatch : BytecodePatch(
@@ -26,9 +33,52 @@ class CustomVideoBufferPatch : BytecodePatch(
)
) {
override fun execute(data: BytecodeData): PatchResult {
SettingsPatch.PreferenceScreen.MISC.addPreferences(
PreferenceScreen(
"revanced_custom_video_buffer",
StringResource("revanced_custom_video_buffer_title", "Video buffer settings"),
listOf(
TextPreference(
"revanced_pref_max_buffer_ms",
StringResource("revanced_pref_max_buffer_ms_title", "Maximum buffer size"),
InputType.NUMBER,
"120000",
StringResource(
"revanced_pref_max_buffer_ms_summary",
"The maximum size of a buffer for playback"
)
),
TextPreference(
"revanced_pref_buffer_for_playback_ms",
StringResource("revanced_pref_buffer_for_playback_ms_title", "Maximum buffer for playback"),
InputType.NUMBER,
"2500",
StringResource(
"revanced_pref_buffer_for_playback_ms_summary",
"Maximum size of a buffer for playback"
)
),
TextPreference(
"revanced_pref_buffer_for_playback_after_rebuffer_ms",
StringResource(
"revanced_pref_buffer_for_playback_after_rebuffer_ms_title",
"Maximum buffer for playback after rebuffer"
),
InputType.NUMBER,
"5000",
StringResource(
"revanced_pref_buffer_for_playback_after_rebuffer_ms_summary",
"Maximum size of a buffer for playback after rebuffering"
)
)
),
StringResource("revanced_custom_video_buffer_summary", "Custom settings for video buffer")
)
)
execMaxBuffer()
execPlaybackBuffer(data)
execReBuffer(data)
execPlaybackBuffer()
execReBuffer()
return PatchResultSuccess()
}
@@ -36,7 +86,7 @@ class CustomVideoBufferPatch : BytecodePatch(
val result = MaxBufferFingerprint.result!!
val method = result.mutableMethod
val index = result.patternScanResult!!.endIndex - 1
val register = (method.implementation!!.instructions.get(index) as OneRegisterInstruction).registerA
val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA
method.addInstructions(
index + 1, """
invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getMaxBuffer()I
@@ -45,11 +95,11 @@ class CustomVideoBufferPatch : BytecodePatch(
)
}
private fun execPlaybackBuffer(data: BytecodeData) {
private fun execPlaybackBuffer() {
val result = PlaybackBufferFingerprint.result!!
val method = result.mutableMethod
val index = result.patternScanResult!!.startIndex
val register = (method.implementation!!.instructions.get(index) as OneRegisterInstruction).registerA
val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA
method.addInstructions(
index + 1, """
invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getPlaybackBuffer()I
@@ -58,7 +108,7 @@ class CustomVideoBufferPatch : BytecodePatch(
)
}
private fun execReBuffer(data: BytecodeData) {
private fun execReBuffer() {
val result = ReBufferFingerprint.result!!
val method = result.mutableMethod
val index = result.patternScanResult!!.startIndex

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