diff --git a/CHANGELOG.md b/CHANGELOG.md index 8637ee96f..3bc2fe7d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,17 @@ +# [2.147.0](https://github.com/revanced/revanced-patches/compare/v2.146.0...v2.147.0) (2022-12-21) + + +### Features + +* **youtube/return-youtube-dislike:** debug connection statistics, toast on error, high priority background threads ([#1320](https://github.com/revanced/revanced-patches/issues/1320)) ([30273a9](https://github.com/revanced/revanced-patches/commit/30273a9bbdd40453baeb09f26ac9d218569a3e71)) + +# [2.147.0-dev.1](https://github.com/revanced/revanced-patches/compare/v2.146.0...v2.147.0-dev.1) (2022-12-21) + + +### Features + +* **youtube/return-youtube-dislike:** debug connection statistics, toast on error, high priority background threads ([#1320](https://github.com/revanced/revanced-patches/issues/1320)) ([30273a9](https://github.com/revanced/revanced-patches/commit/30273a9bbdd40453baeb09f26ac9d218569a3e71)) + # [2.146.0](https://github.com/revanced/revanced-patches/compare/v2.145.0...v2.146.0) (2022-12-18) diff --git a/README.md b/README.md index a01b40018..581ef8d46 100644 --- a/README.md +++ b/README.md @@ -9,53 +9,67 @@ The official Patch bundle provided by ReVanced and the community. | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| -| `always-autorepeat` | Always repeats the playing video again. | 17.49.37 | -| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all | -| `comments` | Hides components related to comments. | 17.49.37 | -| `custom-branding` | Changes the YouTube launcher icon and name to your choice (defaults to ReVanced). | all | +| `client-spoof` | Spoofs the YouTube client to prevent playback issues. | 17.49.37 | +| `custom-branding-icon-blue` | Changes the YouTube launcher icon (ReVanced Blue). | 17.49.37 | +| `custom-branding-icon-red` | Changes the YouTube launcher icon (ReVanced Red). | 17.49.37 | +| `custom-branding-icon-revancify` | Changes the YouTube launcher icon (Revancify). | 17.49.37 | +| `custom-branding-name` | Changes the YouTube launcher name to your choice (defaults to ReVanced Extended). | 17.49.37 | | `custom-video-buffer` | Lets you change the buffers of videos. | 17.49.37 | | `custom-video-speed` | Adds more video speed options. | 17.49.37 | -| `debugging` | Adds debugging options. | all | -| `disable-auto-captions` | Disable forced captions from being automatically enabled. | 17.49.37 | -| `disable-auto-player-popup-panels` | Disable automatic popup panels (playlist or live chat) on video player. | 17.49.37 | -| `disable-fullscreen-panels` | Disables video description and comments panel in fullscreen view. | 17.49.37 | -| `disable-startup-shorts-player` | Disables playing YouTube Shorts when launching YouTube. | 17.49.37 | -| `disable-zoom-haptics` | Disables haptics when zooming. | all | -| `downloads` | Enables downloading music and videos from YouTube. | 17.49.37 | +| `default-video-quality` | Adds ability to set default video quality settings. | 17.49.37 | +| `default-video-speed` | Adds ability to set default video speed settings. | 17.49.37 | +| `disable-haptic-feedback` | Disable haptic feedback when swiping. | 17.49.37 | +| `enable-external-browser` | Use an external browser to open the url. | 17.49.37 | +| `enable-hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.49.37 | +| `enable-minimized-playback` | Enables minimized and background playback. | 17.49.37 | +| `enable-old-layout` | Spoof the YouTube client version to use the old layout. | 17.49.37 | +| `enable-oldstyle-quality-layout` | Enables the original quality flyout menu. | 17.49.37 | +| `enable-open-links-directly` | Bypass URL redirects (youtube.com/redirect) when opening links in video descriptions. | 17.49.37 | +| `enable-seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.49.37 | +| `enable-tablet-miniplayer` | Enables the tablet mini player layout. | 17.49.37 | | `enable-wide-searchbar` | Replaces the search icon with a wide search bar. This will hide the YouTube logo when active. | 17.49.37 | -| `general-ads` | Removes general ads. | 17.49.37 | -| `hdr-auto-brightness` | Makes the brightness of HDR videos follow the system default. | 17.49.37 | -| `hide-album-cards` | Hides the album cards below the artist description. | 17.49.37 | -| `hide-artist-card` | Hides the artist card below the searchbar. | 17.49.37 | +| `force-premium-heading` | Forces premium heading on the home screen. | 17.49.37 | +| `header-switch` | Add switch to change header. | 17.49.37 | +| `hide-auto-captions` | Hide captions from being automatically enabled. | 17.49.37 | +| `hide-auto-player-popup-panels` | Hide automatic popup panels (playlist or live chat) on video player. | 17.49.37 | | `hide-autoplay-button` | Hides the autoplay button in the video player. | 17.49.37 | -| `hide-captions-button` | Hides the captions button on video player. | 17.49.37 | -| `hide-cast-button` | Hides the cast button in the video player. | all | +| `hide-button-container` | Adds options to hide action buttons under a video. | 17.49.37 | +| `hide-cast-button` | Hides the cast button in the video player. | 17.49.37 | +| `hide-channel-watermark` | Hides creator's watermarks on videos. | 17.49.37 | +| `hide-comment-component` | Adds options to hide comment component under a video. | 17.49.37 | | `hide-create-button` | Hides the create button in the navigation bar. | 17.49.37 | | `hide-crowdfunding-box` | Hides the crowdfunding box between the player and video description. | 17.49.37 | | `hide-email-address` | Hides the email address in the account switcher. | 17.49.37 | | `hide-endscreen-cards` | Hides the suggested video cards at the end of a video in fullscreen. | 17.49.37 | +| `hide-endscreen-overlay` | Hide endscreen overlay on swipe controls. | 17.49.37 | +| `hide-filmstrip-overlay` | Hide flimstrip overlay on swipe controls. | 17.49.37 | +| `hide-flyout-panel` | Adds options to hide player settings flyout panel. | 17.49.37 | +| `hide-fullscreen-buttoncontainer` | Hides the button containers in fullscreen. | 17.49.37 | +| `hide-general-ads` | Hooks the method which parses the bytes into a ComponentContext to filter components. | 17.49.37 | | `hide-info-cards` | Hides info-cards in videos. | 17.49.37 | -| `hide-my-mix` | Hides mix playlists. | 17.49.37 | -| `hide-shorts-button` | Hides the shorts button on the navigation bar. | 17.49.37 | +| `hide-mix-playlists` | Removes mix playlists from home feed and video player. | 17.49.37 | +| `hide-pip-notification` | Disable pip notification when you first launch pip mode. | 17.49.37 | +| `hide-player-captions-button` | Hides the captions button in the video player. | 17.49.37 | +| `hide-player-overlay-filter` | Hide the suggested actions bar inside the player. | 17.49.37 | +| `hide-shorts-button` | Hides the shorts button in the navigation bar. | 17.49.37 | +| `hide-shorts-component` | Hides other Shorts components. | 17.49.37 | +| `hide-startup-shorts-player` | Disables playing YouTube Shorts when launching YouTube. | 17.49.37 | +| `hide-stories` | Hides YouTube Stories shelf on the feed. | 17.49.37 | +| `hide-suggested-actions` | Hide the suggested actions bar inside the player. | 17.49.37 | | `hide-time-and-seekbar` | Hides progress bar and time counter on videos. | 17.49.37 | -| `hide-video-buttons` | Adds options to hide action buttons under a video. | 17.49.37 | -| `hide-watch-in-vr` | Hides the Watch in VR option in the player settings flyout panel. | 17.49.37 | -| `hide-watermark` | Hides creator's watermarks on videos. | 17.49.37 | +| `hide-video-ads` | Removes ads in the video player. | 17.49.37 | +| `layout-switch` | Tricks the dpi to use some tablet/phone layouts. | 17.49.37 | +| `materialyou` | Enables MaterialYou theme for Android 12+ | 17.49.37 | | `microg-support` | Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG. | 17.49.37 | -| `minimized-playback` | Enables minimized and background playback. | 17.49.37 | -| `old-quality-layout` | Enables the original video quality flyout in the video player settings | 17.49.37 | -| `open-links-directly` | Bypasses URL redirects and opens links directly inside YouTube app. | 17.49.37 | -| `premium-heading` | Shows premium branding on the home screen. | all | -| `remember-video-quality` | Adds the ability to remember the video quality you chose in the video quality flyout. | 17.49.37 | +| `optimize-resource` | Removes duplicate resources and adds missing translation files from YouTube. | 17.49.37 | +| `overlay-buttons` | Add overlay buttons for ReVanced Extended. | 17.49.37 | | `remove-player-button-background` | Removes the background from the video player buttons. | 17.49.37 | | `return-youtube-dislike` | Shows the dislike count of videos using the Return YouTube Dislike API. | 17.49.37 | -| `seekbar-tapping` | Enables tap-to-seek on the seekbar of the video player. | 17.49.37 | -| `settings` | Adds settings for ReVanced to YouTube. | all | +| `settings` | Applies mandatory patches to implement ReVanced settings into the application. | 17.49.37 | | `sponsorblock` | Integrate SponsorBlock. | 17.49.37 | | `swipe-controls` | Adds volume and brightness swipe controls. | 17.49.37 | -| `tablet-mini-player` | Enables the tablet mini player layout. | 17.49.37 | -| `theme` | Applies a custom theme. | all | -| `video-ads` | Removes ads in the video player. | 17.49.37 | +| `theme` | Applies a custom theme (default: amoled). | 17.49.37 | +| `translations` | Add Crowdin Translations | 17.49.37 | ### [📦 `com.google.android.apps.youtube.music`](https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music) @@ -63,186 +77,27 @@ The official Patch bundle provided by ReVanced and the community. | 💊 Patch | 📜 Description | 🏹 Target Version | |:--------:|:--------------:|:-----------------:| -| `background-play` | Enables playing music in the background. | 5.36.51 | -| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | 5.36.51 | -| `compact-header` | Hides the music category bar at the top of the homepage. | 5.36.51 | -| `exclusive-audio-playback` | Enables the option to play music without video. | 5.36.51 | -| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | 5.36.51 | -| `minimized-playback-music` | Enables minimized playback on Kids music. | 5.36.51 | -| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | 5.36.51 | -| `music-video-ads` | Removes ads in the music player. | 5.36.51 | -| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | 5.36.51 | -| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | 5.36.51 | - - -### [📦 `com.ss.android.ugc.trill`](https://play.google.com/store/apps/details?id=com.ss.android.ugc.trill) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `disable-login-requirement` | Do not force login. | all | -| `downloads` | Removes download restrictions and changes the default path to download to. | all | -| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | all | -| `fix-google-login` | Allows logging in with a Google account. | all | -| `hide-ads` | Removes ads from TikTok. | all | -| `playback-speed` | Enables the playback speed option for all videos. | all | -| `settings` | Adds ReVanced settings to TikTok. | all | -| `show-seekbar` | Shows progress bar for all video. | all | -| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | all | -
- -### [📦 `com.zhiliaoapp.musically`](https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `disable-login-requirement` | Do not force login. | all | -| `downloads` | Removes download restrictions and changes the default path to download to. | all | -| `feed-filter` | Filters tiktok videos: removing ads, removing livestreams. | all | -| `fix-google-login` | Allows logging in with a Google account. | all | -| `hide-ads` | Removes ads from TikTok. | all | -| `playback-speed` | Enables the playback speed option for all videos. | all | -| `settings` | Adds ReVanced settings to TikTok. | all | -| `show-seekbar` | Shows progress bar for all video. | all | -| `sim-spoof` | Spoofs the information which is retrieved from the sim-card. | all | -
- -### [📦 `tv.twitch.android.app`](https://play.google.com/store/apps/details?id=tv.twitch.android.app) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `block-audio-ads` | Blocks audio ads in streams and VODs. | all | -| `block-embedded-ads` | Blocks embedded steam ads using services like TTV.lol or PurpleAdBlocker. | all | -| `block-video-ads` | Blocks video ads in streams and VODs. | all | -| `debug-mode` | Enables Twitch's internal debugging mode. | all | -| `settings` | Adds settings menu to Twitch. | all | -| `show-deleted-messages` | Shows deleted chat messages behind a clickable spoiler. | all | -
- -### [📦 `com.spotify.music`](https://play.google.com/store/apps/details?id=com.spotify.music) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `disable-capture-restriction` | Allows capturing Spotify's audio output while screen sharing or screen recording. | all | -| `hide-premium-navbar` | Removes the premium tab from the navbar. | all | -| `spotify-theme` | Applies a custom theme. | all | -
- -### [📦 `com.twitter.android`](https://play.google.com/store/apps/details?id=com.twitter.android) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `dynamic-color` | Replaces the default Twitter Blue with the users Material You palette. | all | -| `monochrome-icon` | Adds a monochrome icon. | all | -| `timeline-ads` | Removes ads from the Twitter timeline. Might require clearing app data to remove already cached ads. | all | -
- -### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `general-reddit-ads` | Removes general ads from the Reddit frontpage and subreddits. | all | -| `premium-icon-reddit` | Unlocks premium Reddit app icons. | all | -
- -### [📦 `com.vanced.android.youtube`](https://play.google.com/store/apps/details?id=com.vanced.android.youtube) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `client-spoof` | Spoofs the YouTube or Vanced client to prevent playback issues. | all | -
- -### [📦 `com.myprog.hexedit`](https://play.google.com/store/apps/details?id=com.myprog.hexedit) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `disable-ads` | Disables ads in HexEditor. | all | -
- -### [📦 `org.citra.citra_emu`](https://play.google.com/store/apps/details?id=org.citra.citra_emu) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `premium-unlock` | Unlocks premium functions. | all | -
- -### [📦 `org.citra.citra_emu.canary`](https://play.google.com/store/apps/details?id=org.citra.citra_emu.canary) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `premium-unlock` | Unlocks premium functions. | all | -
- -### [📦 `com.backdrops.wallpapers`](https://play.google.com/store/apps/details?id=com.backdrops.wallpapers) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `pro-unlock` | Unlocks pro-only functions. | all | -
- -### [📦 `de.dwd.warnapp`](https://play.google.com/store/apps/details?id=de.dwd.warnapp) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `promo-code-unlock` | Disables the validation of promo code. Any code will work to unlock all features. | all | -
- -### [📦 `co.windyapp.android`](https://play.google.com/store/apps/details?id=co.windyapp.android) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks all pro features. | all | -
- -### [📦 `org.totschnig.myexpenses`](https://play.google.com/store/apps/details?id=org.totschnig.myexpenses) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks all professional features. | all | -
- -### [📦 `com.awedea.nyx`](https://play.google.com/store/apps/details?id=com.awedea.nyx) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks all pro features. | all | -
- -### [📦 `com.ithebk.expensemanager`](https://play.google.com/store/apps/details?id=com.ithebk.expensemanager) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks pro features. | all | -
- -### [📦 `ginlemon.iconpackstudio`](https://play.google.com/store/apps/details?id=ginlemon.iconpackstudio) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-pro` | Unlocks all pro features. | all | -
- -### [📦 `com.ticktick.task`](https://play.google.com/store/apps/details?id=com.ticktick.task) -
- -| 💊 Patch | 📜 Description | 🏹 Target Version | -|:--------:|:--------------:|:-----------------:| -| `unlock-themes` | Unlocks all themes. | all | +| `background-play` | Enables playing music in the background. | all | +| `black-navbar` | Sets the navigation bar color to black. | all | +| `client-spoof-music` | Spoofs the YouTube Music client. | all | +| `codecs-unlock` | Adds more audio codec options. The new audio codecs usually result in better audio quality. | all | +| `compact-header` | Hides the music category bar at the top of the homepage. | all | +| `custom-branding-music-red` | Changes the YouTube Music launcher icon to your choice (defaults to ReVanced Red). | all | +| `custom-branding-music-revancify` | Changes the YouTube Music launcher icon to your choice (Revancify). | all | +| `exclusive-audio-playback` | Enables the option to play music without video. | all | +| `hide-get-premium` | Removes all "Get Premium" evidences from the avatar menu. | all | +| `hide-music-cast-button` | Hides the cast button in the video player and header | all | +| `minimized-playback-music` | Enables minimized playback on Kids music. | all | +| `minimized-player` | Permanently keep player minimized even if another track is played. | all | +| `miniplayer-color` | Matches the fullscreen player color with the minimized one. | all | +| `music-microg-support` | Allows YouTube Music ReVanced to run without root and under a different package name. | all | +| `music-settings` | Adds settings for ReVanced to YouTube Music. | all | +| `music-video-ads` | Removes ads in the music player. | all | +| `optimize-resource-music` | Remove unnecessary resources. | all | +| `tablet-mode` | Unlocks landscape mode. | all | +| `tasteBuilder-remover` | Removes the "Tell us which artists you like" card from the home screen. | all | +| `translations-music` | Add Crowdin Translations for YouTube Music | all | +| `upgrade-button-remover` | Removes the upgrade tab from the pivot bar. | all |
@@ -288,76 +143,10 @@ Example: { "name": "com.google.android.youtube", "versions": [ - "17.22.36", - "17.24.35", - "17.26.35", - "17.27.39", - "17.28.34", - "17.29.34", - "17.32.35", - "17.33.42" + "17.49.37" ] } ] - }, - { - "name": "theme", - "description": "Enables a custom theme.", - "version": "0.0.1", - "excluded": false, - "deprecated": false, - "options": [ - { - "key": "theme", - "title": "Theme", - "description": "Select a theme.", - "required": true, - "choices": [ - "Amoled" - ] - } - ], - "dependencies": [ - "locale-config-fix" - ], - "compatiblePackages": [ - { - "name": "com.google.android.youtube", - "versions": [] - } - ] - }, - { - "name": "custom-branding", - "description": "Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).", - "version": "0.0.1", - "excluded": false, - "deprecated": false, - "options": [ - { - "key": "appName", - "title": "Application Name", - "description": "The name of the application it will show on your home screen.", - "required": true, - "choices": null - }, - { - "key": "appIconPath", - "title": "Application Icon Path", - "description": "A path to the icon of the application.", - "required": false, - "choices": null - } - ], - "dependencies": [ - "locale-config-fix" - ], - "compatiblePackages": [ - { - "name": "com.google.android.youtube", - "versions": [] - } - ] } ] ``` \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index cd9bb6605..e86916520 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ kotlin.code.style = official -version = 2.146.0 +version = 2.147.0 diff --git a/patches.json b/patches.json index 934ee20da..83f03229a 100644 --- a/patches.json +++ b/patches.json @@ -1 +1 @@ -[{"name":"always-autorepeat","description":"Always repeats the playing video again.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"background-play","description":"Enables playing music in the background.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"block-audio-ads","description":"Blocks audio ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"block-embedded-ads","description":"Blocks embedded steam ads using services like TTV.lol or PurpleAdBlocker.","version":"0.0.1","excluded":false,"options":[],"dependencies":["block-video-ads","integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"block-video-ads","description":"Blocks video ads in streams and VODs.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"client-spoof","description":"Spoofs the YouTube or Vanced client to prevent playback issues.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]},{"name":"com.vanced.android.youtube","versions":[]}]},{"name":"codecs-unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"comments","description":"Hides components related to comments.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","comments-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"compact-header","description":"Hides the music category bar at the top of the homepage.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"custom-branding","description":"Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).","version":"0.0.1","excluded":false,"options":[{"key":"appName","title":"Application Name","description":"The name of the application it will show on your home screen.","required":true,"choices":null},{"key":"iconPath","title":"App Icon Path","description":"A path containing mipmap resource folders with icons.","required":false,"choices":null}],"dependencies":["locale-config-fix"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"custom-video-buffer","description":"Lets you change the buffers of videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"custom-video-speed","description":"Adds more video speed options.","version":"0.0.1","excluded":false,"options":[{"key":"granularity","title":"Video speed granularity","description":"The granularity of the video speeds. The higher the value, the more speeds will be available.","required":true,"choices":null},{"key":"min","title":"Minimum video speed","description":"The minimum video speed.","required":true,"choices":null},{"key":"max","title":"Maximum video speed","description":"The maximum video speed. Must be greater than the minimum video speed and smaller than 5.","required":true,"choices":null}],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"debug-mode","description":"Enables Twitch\u0027s internal debugging mode.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"debugging","description":"Adds debugging options.","version":"0.0.1","excluded":false,"options":[{"key":"debuggable","title":"App debugging","description":"Whether to make the app debuggable on Android.","required":false,"choices":null}],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"disable-ads","description":"Disables ads in HexEditor.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.myprog.hexedit","versions":[]}]},{"name":"disable-auto-captions","description":"Disable forced captions from being automatically enabled.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"disable-auto-player-popup-panels","description":"Disable automatic popup panels (playlist or live chat) on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"disable-capture-restriction","description":"Allows capturing Spotify\u0027s audio output while screen sharing or screen recording.","version":"0.0.2","excluded":false,"options":[],"dependencies":["disable-capture-restriction-resource-patch"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"disable-fullscreen-panels","description":"Disables video description and comments panel in fullscreen view.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"disable-login-requirement","description":"Do not force login.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"disable-startup-shorts-player","description":"Disables playing YouTube Shorts when launching YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"disable-zoom-haptics","description":"Disables haptics when zooming.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"downloads","description":"Enables downloading music and videos from YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["downloads-resource-patch","player-controls-bytecode-patch","video-id-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"downloads","description":"Removes download restrictions and changes the default path to download to.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"dynamic-color","description":"Replaces the default Twitter Blue with the users Material You palette.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"enable-wide-searchbar","description":"Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"exclusive-audio-playback","description":"Enables the option to play music without video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"feed-filter","description":"Filters tiktok videos: removing ads, removing livestreams.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"fix-google-login","description":"Allows logging in with a Google account.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"general-ads","description":"Removes general ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":["GeneralAdsResourcePatch","VerticalScrollPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"general-reddit-ads","description":"Removes general ads from the Reddit frontpage and subreddits.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"hdr-auto-brightness","description":"Makes the brightness of HDR videos follow the system default.","version":"0.0.2","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-ads","description":"Removes ads from TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"hide-album-cards","description":"Hides the album cards below the artist description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-album-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-artist-card","description":"Hides the artist card below the searchbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-autoplay-button","description":"Hides the autoplay button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-captions-button","description":"Hides the captions button on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-cast-button","description":"Hides the cast button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"hide-create-button","description":"Hides the create button in the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","resource-mapping","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-crowdfunding-box","description":"Hides the crowdfunding box between the player and video description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","crowdfunding-box-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-email-address","description":"Hides the email address in the account switcher.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-email-address-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-endscreen-cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","hide-endscreen-cards-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-get-premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"hide-info-cards","description":"Hides info-cards in videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","HideInfocardsResourcePatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-my-mix","description":"Hides mix playlists.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-premium-navbar","description":"Removes the premium tab from the navbar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"hide-shorts-button","description":"Hides the shorts button on the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","ResolvePivotBarFingerprintsPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-time-and-seekbar","description":"Hides progress bar and time counter on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-video-buttons","description":"Adds options to hide action buttons under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["resource-mapping","LithoFilterPatch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-watch-in-vr","description":"Hides the Watch in VR option in the player settings flyout panel.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-watermark","description":"Hides creator\u0027s watermarks on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"microg-support","description":"Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.","version":"0.0.1","excluded":false,"options":[],"dependencies":["microg-resource-patch","hide-cast-button","client-spoof"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"minimized-playback","description":"Enables minimized and background playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"minimized-playback-music","description":"Enables minimized playback on Kids music.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"monochrome-icon","description":"Adds a monochrome icon.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"music-microg-support","description":"Allows YouTube Music ReVanced to run without root and under a different package name.","version":"0.0.2","excluded":false,"options":[],"dependencies":["music-microg-resource-patch"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"music-video-ads","description":"Removes ads in the music player.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"old-quality-layout","description":"Enables the original video quality flyout in the video player settings","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"open-links-directly","description":"Bypasses URL redirects and opens links directly inside YouTube app.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"playback-speed","description":"Enables the playback speed option for all videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"predictive-back-gesture","description":"Enables the predictive back gesture introduced on Android 13.","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[]},{"name":"premium-heading","description":"Shows premium branding on the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["locale-config-fix"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"premium-icon-reddit","description":"Unlocks premium Reddit app icons.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.reddit.frontpage","versions":[]}]},{"name":"premium-unlock","description":"Unlocks premium functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.citra.citra_emu","versions":[]},{"name":"org.citra.citra_emu.canary","versions":[]}]},{"name":"pro-unlock","description":"Unlocks pro-only functions.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.backdrops.wallpapers","versions":[]}]},{"name":"promo-code-unlock","description":"Disables the validation of promo code. Any code will work to unlock all features.","version":"0.0.1","excluded":false,"options":[],"dependencies":["spoof-cert-patch"],"compatiblePackages":[{"name":"de.dwd.warnapp","versions":[]}]},{"name":"remember-video-quality","description":"Adds the ability to remember the video quality you chose in the video quality flyout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"remove-player-button-background","description":"Removes the background from the video player buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["locale-config-fix"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"return-youtube-dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","video-id-hook","return-youtube-dislike-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"settings","description":"Adds settings for ReVanced to YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"settings","description":"Adds settings menu to Twitch.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings-resource-patch"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"settings","description":"Adds ReVanced settings to TikTok.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"show-deleted-messages","description":"Shows deleted chat messages behind a clickable spoiler.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"tv.twitch.android.app","versions":[]}]},{"name":"show-seekbar","description":"Shows progress bar for all video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sim-spoof","description":"Spoofs the information which is retrieved from the sim-card.","version":"0.0.1","excluded":true,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.ss.android.ugc.trill","versions":[]},{"name":"com.zhiliaoapp.musically","versions":[]}]},{"name":"sponsorblock","description":"Integrate SponsorBlock.","version":"0.0.1","excluded":false,"options":[],"dependencies":["video-information","player-controls-bytecode-patch","integrations","sponsorblock-resource-patch","video-id-hook"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"spotify-theme","description":"Applies a custom theme.","version":"0.0.1","excluded":false,"options":[{"key":"backgroundColor","title":"Background color","description":"The background color. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentColor","title":"Accent color","description":"The accent color (\u0027spotify green\u0027 by default). Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"accentPressedColor","title":"Pressed accent for the dark theme","description":"The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":["locale-config-fix"],"compatiblePackages":[{"name":"com.spotify.music","versions":[]}]},{"name":"swipe-controls","description":"Adds volume and brightness swipe controls.","version":"0.0.3","excluded":false,"options":[],"dependencies":["integrations","player-type-hook","swipe-controls-resource-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"tablet-mini-player","description":"Enables the tablet mini player layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"tasteBuilder-remover","description":"Removes the \"Tell us which artists you like\" card from the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"theme","description":"Applies a custom theme.","version":"0.0.1","excluded":true,"options":[{"key":"darkThemeBackgroundColor","title":"Background color for the dark theme","description":"The background color of the dark theme. Can be a hex color or a resource reference.","required":false,"choices":null},{"key":"lightThemeBackgroundColor","title":"Background color for the light theme","description":"The background color of the light theme. Can be a hex color or a resource reference.","required":false,"choices":null}],"dependencies":["litho-components-theme","locale-config-fix"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":[]}]},{"name":"timeline-ads","description":"Removes ads from the Twitter timeline. Might require clearing app data to remove already cached ads.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.twitter.android","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"co.windyapp.android","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all professional features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"org.totschnig.myexpenses","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.awedea.nyx","versions":[]}]},{"name":"unlock-pro","description":"Unlocks pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ithebk.expensemanager","versions":[]}]},{"name":"unlock-pro","description":"Unlocks all pro features.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"ginlemon.iconpackstudio","versions":[]}]},{"name":"unlock-themes","description":"Unlocks all themes.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.ticktick.task","versions":[]}]},{"name":"upgrade-button-remover","description":"Removes the upgrade tab from the pivot bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":["5.14.53","5.16.51","5.17.51","5.21.52","5.22.54","5.23.50","5.25.51","5.25.52","5.26.52","5.27.51","5.28.52","5.29.52","5.31.50","5.34.51","5.36.51"]}]},{"name":"video-ads","description":"Removes ads in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["integrations","settings","fix-playback"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]}] \ No newline at end of file +[{"name":"background-play","description":"Enables playing music in the background.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"black-navbar","description":"Sets the navigation bar color to black.","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"client-spoof","description":"Spoofs the YouTube client to prevent playback issues.","version":"0.0.1","excluded":false,"options":[],"dependencies":["client-spoof-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"client-spoof-music","description":"Spoofs the YouTube Music client.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"codecs-unlock","description":"Adds more audio codec options. The new audio codecs usually result in better audio quality.","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"compact-header","description":"Hides the music category bar at the top of the homepage.","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"custom-branding-icon-blue","description":"Changes the YouTube launcher icon (ReVanced Blue).","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"custom-branding-icon-red","description":"Changes the YouTube launcher icon (ReVanced Red).","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"custom-branding-icon-revancify","description":"Changes the YouTube launcher icon (Revancify).","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"custom-branding-music-red","description":"Changes the YouTube Music launcher icon to your choice (defaults to ReVanced Red).","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"custom-branding-music-revancify","description":"Changes the YouTube Music launcher icon to your choice (Revancify).","version":"0.0.1","excluded":true,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"custom-branding-name","description":"Changes the YouTube launcher name to your choice (defaults to ReVanced Extended).","version":"0.0.1","excluded":false,"options":[],"dependencies":["patch-options","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"custom-video-buffer","description":"Lets you change the buffers of videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["custom-video-buffer-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"custom-video-speed","description":"Adds more video speed options.","version":"0.0.1","excluded":false,"options":[],"dependencies":["custom-speed-bytecode-patch","patch-options","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"default-video-quality","description":"Adds ability to set default video quality settings.","version":"0.0.1","excluded":false,"options":[],"dependencies":["default-video-quality-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"default-video-speed","description":"Adds ability to set default video speed settings.","version":"0.0.1","excluded":false,"options":[],"dependencies":["default-video-speed-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"disable-haptic-feedback","description":"Disable haptic feedback when swiping.","version":"0.0.1","excluded":false,"options":[],"dependencies":["disable-haptic-feedback-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-external-browser","description":"Use an external browser to open the url.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-external-browser-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-hdr-auto-brightness","description":"Makes the brightness of HDR videos follow the system default.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-hdr-auto-brightness-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-minimized-playback","description":"Enables minimized and background playback.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-minimized-playback-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-old-layout","description":"Spoof the YouTube client version to use the old layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-old-layout-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-oldstyle-quality-layout","description":"Enables the original quality flyout menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-oldstyle-quality-layout-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-open-links-directly","description":"Bypass URL redirects (youtube.com/redirect) when opening links in video descriptions.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-open-links-directly-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-seekbar-tapping","description":"Enables tap-to-seek on the seekbar of the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-seekbar-tapping-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-tablet-miniplayer","description":"Enables the tablet mini player layout.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-tablet-miniplayer-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"enable-wide-searchbar","description":"Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.","version":"0.0.1","excluded":false,"options":[],"dependencies":["enable-wide-searchbar-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"exclusive-audio-playback","description":"Enables the option to play music without video.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"force-premium-heading","description":"Forces premium heading on the home screen.","version":"0.0.1","excluded":true,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"header-switch","description":"Add switch to change header.","version":"0.0.1","excluded":false,"options":[],"dependencies":["header-switch-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-auto-captions","description":"Hide captions from being automatically enabled.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-auto-captions-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-auto-player-popup-panels","description":"Hide automatic popup panels (playlist or live chat) on video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-auto-player-popup-panels-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-autoplay-button","description":"Hides the autoplay button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-autoplay-button-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-button-container","description":"Adds options to hide action buttons under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["LithoFilterPatch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-cast-button","description":"Hides the cast button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-cast-button-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-channel-watermark","description":"Hides creator\u0027s watermarks on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-channel-watermark-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-comment-component","description":"Adds options to hide comment component under a video.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-general-ads-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-create-button","description":"Hides the create button in the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-create-button-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-crowdfunding-box","description":"Hides the crowdfunding box between the player and video description.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-crowdfunding-box-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-email-address","description":"Hides the email address in the account switcher.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-email-address-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-endscreen-cards","description":"Hides the suggested video cards at the end of a video in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-endscreen-cards-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-endscreen-overlay","description":"Hide endscreen overlay on swipe controls.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-endscreen-overlay-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-filmstrip-overlay","description":"Hide flimstrip overlay on swipe controls.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-filmstrip-overlay-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-flyout-panel","description":"Adds options to hide player settings flyout panel.","version":"0.0.1","excluded":false,"options":[],"dependencies":["LithoFilterPatch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-fullscreen-buttoncontainer","description":"Hides the button containers in fullscreen.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-fullscreen-buttoncontainer-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-general-ads","description":"Hooks the method which parses the bytes into a ComponentContext to filter components.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-general-ads-bytecode-patch","hide-general-ads-secondary-bytecode-patch","LithoFilterPatch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-get-premium","description":"Removes all \"Get Premium\" evidences from the avatar menu.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"hide-info-cards","description":"Hides info-cards in videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-info-cards-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-mix-playlists","description":"Removes mix playlists from home feed and video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["LithoFilterPatch","hide-mix-playlists-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-music-cast-button","description":"Hides the cast button in the video player and header","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"hide-pip-notification","description":"Disable pip notification when you first launch pip mode.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-pip-notification-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-player-captions-button","description":"Hides the captions button in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-captions-button-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-player-overlay-filter","description":"Hide the suggested actions bar inside the player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","hide-player-overlay-filter-bytecode-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-shorts-button","description":"Hides the shorts button in the navigation bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-shorts-button","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-shorts-component","description":"Hides other Shorts components.","version":"0.0.1","excluded":false,"options":[],"dependencies":["LithoFilterPatch","hide-shorts-component-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-startup-shorts-player","description":"Disables playing YouTube Shorts when launching YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-startup-shorts-player-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-stories","description":"Hides YouTube Stories shelf on the feed.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-stories-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-suggested-actions","description":"Hide the suggested actions bar inside the player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","hide-suggested-actions-bytecode-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-time-and-seekbar","description":"Hides progress bar and time counter on videos.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-time-and-seekbar-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"hide-video-ads","description":"Removes ads in the video player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["hide-video-ads-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"layout-switch","description":"Tricks the dpi to use some tablet/phone layouts.","version":"0.0.1","excluded":false,"options":[],"dependencies":["layout-switch-bytecode-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"materialyou","description":"Enables MaterialYou theme for Android 12+","version":"0.0.1","excluded":true,"options":[],"dependencies":["general-theme","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"microg-support","description":"Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","microg-support-bytecode-patch","patch-options"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"minimized-playback-music","description":"Enables minimized playback on Kids music.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"minimized-player","description":"Permanently keep player minimized even if another track is played.","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"miniplayer-color","description":"Matches the fullscreen player color with the minimized one.","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-microg-support","description":"Allows YouTube Music ReVanced to run without root and under a different package name.","version":"0.0.2","excluded":false,"options":[],"dependencies":["client-spoof-music","music-microg-resource-patch","patch-options"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-settings","description":"Adds settings for ReVanced to YouTube Music.","version":"0.0.1","excluded":false,"options":[],"dependencies":["locale-config-fix"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"music-video-ads","description":"Removes ads in the music player.","version":"0.0.1","excluded":false,"options":[],"dependencies":["general-video-ads-patch","music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"optimize-resource","description":"Removes duplicate resources and adds missing translation files from YouTube.","version":"0.0.1","excluded":false,"options":[],"dependencies":["remove-duplicate-resource-patch","add-missing-transition-patch","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"optimize-resource-music","description":"Remove unnecessary resources.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"overlay-buttons","description":"Add overlay buttons for ReVanced Extended.","version":"0.0.1","excluded":false,"options":[],"dependencies":["always-autorepeat","overlay-buttons-bytecode-patch","patch-options","settings","channel-whitelist"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"patch-options","description":"Create an options.toml file.","version":"0.0.1","excluded":false,"options":[{"key":"YouTube_AppName","title":"Application Name of YouTube","description":"The name of the YouTube it will show on your home screen.","required":true,"choices":null},{"key":"YouTube_PackageName","title":"Package Name of YouTube","description":"The package name of the YouTube. (NON-ROOT user only)","required":true,"choices":null},{"key":"Music_PackageName","title":"Package Name of YouTube Music","description":"The package name of the YouTube Music. (NON-ROOT user only)","required":true,"choices":null},{"key":"Custom_Speed_Arrays","title":"Custom Speed Values","description":"A list of custom video speeds. Be sure to separate them with commas (,).","required":true,"choices":null},{"key":"Overlay_Buttons_Icon","title":"Overlay button icon selection","description":"Choose an overlay buttons icon (old/new)","required":true,"choices":null},{"key":"darkThemeBackgroundColor","title":"Background color for the dark theme","description":"The background color of the dark theme. Can be a hex color or a resource reference.","required":true,"choices":null}],"dependencies":[],"compatiblePackages":[]},{"name":"remove-player-button-background","description":"Removes the background from the video player buttons.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"return-youtube-dislike","description":"Shows the dislike count of videos using the Return YouTube Dislike API.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","return-youtube-dislike-bytecode-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"settings","description":"Applies mandatory patches to implement ReVanced settings into the application.","version":"0.0.1","excluded":false,"options":[],"dependencies":["locale-config-fix","integrations","shared-resource-id","settings-bytecode-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"sponsorblock","description":"Integrate SponsorBlock.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","sponsorblock-bytecode-patch","sponsorblock-secondary-bytecode-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"swipe-controls","description":"Adds volume and brightness swipe controls.","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings","swipe-controls-bytecode-patch"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"tablet-mode","description":"Unlocks landscape mode.","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings","resource-mapping"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"tasteBuilder-remover","description":"Removes the \"Tell us which artists you like\" card from the home screen.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"theme","description":"Applies a custom theme (default: amoled).","version":"0.0.1","excluded":false,"options":[],"dependencies":["general-theme","patch-options","settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"translations","description":"Add Crowdin Translations","version":"0.0.1","excluded":false,"options":[],"dependencies":["settings"],"compatiblePackages":[{"name":"com.google.android.youtube","versions":["17.49.37"]}]},{"name":"translations-music","description":"Add Crowdin Translations for YouTube Music","version":"0.0.1","excluded":false,"options":[],"dependencies":["music-integrations","music-settings"],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]},{"name":"upgrade-button-remover","description":"Removes the upgrade tab from the pivot bar.","version":"0.0.1","excluded":false,"options":[],"dependencies":[],"compatiblePackages":[{"name":"com.google.android.apps.youtube.music","versions":[]}]}] \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/annotations/ProUnlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/annotations/ProUnlockCompatibility.kt deleted file mode 100644 index 60b4832c5..000000000 --- a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/annotations/ProUnlockCompatibility.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.patches.backdrops.misc.pro.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.backdrops.wallpapers")]) -internal annotation class ProUnlockCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt deleted file mode 100644 index 7deff0a9c..000000000 --- a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/fingerprints/ProUnlockFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.backdrops.misc.pro.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object ProUnlockFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ - ), - customFingerprint = { it.definingClass == "Lcom/backdrops/wallpapers/data/local/DatabaseHandlerIAB;" && it.name == "lambda\$existPurchase\$0" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt deleted file mode 100644 index 0365284d8..000000000 --- a/src/main/kotlin/app/revanced/patches/backdrops/misc/pro/patch/ProUnlockPatch.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.backdrops.misc.pro.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.MethodFingerprintExtensions.name -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.backdrops.misc.pro.annotations.ProUnlockCompatibility -import app.revanced.patches.backdrops.misc.pro.fingerprints.ProUnlockFingerprint -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@Name("pro-unlock") -@Description("Unlocks pro-only functions.") -@ProUnlockCompatibility -@Version("0.0.1") -class ProUnlockPatch : BytecodePatch( - listOf(ProUnlockFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - val result = ProUnlockFingerprint.result ?: return PatchResultError("${ProUnlockFingerprint.name} not found") - - val moveRegisterInstruction = result.mutableMethod.instruction(result.scanResult.patternScanResult!!.endIndex - 1) - val register = (moveRegisterInstruction as OneRegisterInstruction).registerA - - result.mutableMethod.addInstructions( - result.scanResult.patternScanResult!!.endIndex, - """ - const/4 v$register, 0x1 - """ - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/citra/misc/premium/annotations/PremiumUnlockCompatbility.kt b/src/main/kotlin/app/revanced/patches/citra/misc/premium/annotations/PremiumUnlockCompatbility.kt deleted file mode 100644 index a40ee1443..000000000 --- a/src/main/kotlin/app/revanced/patches/citra/misc/premium/annotations/PremiumUnlockCompatbility.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.patches.citra.misc.premium.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("org.citra.citra_emu"), Package("org.citra.citra_emu.canary")]) -internal annotation class PremiumUnlockCompatbility diff --git a/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt deleted file mode 100644 index 347c31a2d..000000000 --- a/src/main/kotlin/app/revanced/patches/citra/misc/premium/fingerprints/PremiumUnlockFingerprint.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.patches.citra.misc.premium.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object PremiumUnlockFingerprint : MethodFingerprint( - customFingerprint = { it.definingClass == "Lorg/citra/citra_emu/ui/main/MainActivity;" && it.name == "isPremiumActive" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/citra/misc/premium/patch/PremiumUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/citra/misc/premium/patch/PremiumUnlockPatch.kt deleted file mode 100644 index 10d4eebea..000000000 --- a/src/main/kotlin/app/revanced/patches/citra/misc/premium/patch/PremiumUnlockPatch.kt +++ /dev/null @@ -1,37 +0,0 @@ -package app.revanced.patches.citra.misc.premium.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.MethodFingerprintExtensions.name -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patches.citra.misc.premium.annotations.PremiumUnlockCompatbility -import app.revanced.patches.citra.misc.premium.fingerprints.PremiumUnlockFingerprint - -@Patch -@Name("premium-unlock") -@Description("Unlocks premium functions.") -@PremiumUnlockCompatbility -@Version("0.0.1") -class PremiumUnlockPatch : BytecodePatch( - listOf(PremiumUnlockFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - val result = PremiumUnlockFingerprint.result ?: return PatchResultError("${PremiumUnlockFingerprint.name} not found") - - result.mutableMethod.addInstructions( - 0, - """ - const v0, 0x1 - return v0 - """ - ) - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/hexeditor/ad/annotations/HexEditorAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/hexeditor/ad/annotations/HexEditorAdsCompatibility.kt deleted file mode 100644 index e0ae0e0be..000000000 --- a/src/main/kotlin/app/revanced/patches/hexeditor/ad/annotations/HexEditorAdsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.hexeditor.ad.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.myprog.hexedit") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HexEditorAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt deleted file mode 100644 index 34c3e94af..000000000 --- a/src/main/kotlin/app/revanced/patches/hexeditor/ad/fingerprints/PrimaryAdsFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.hexeditor.ad.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object PrimaryAdsFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("PreferencesHelper;") && methodDef.name == "isAdsDisabled" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/hexeditor/ad/patch/HexEditorAdsPatch.kt b/src/main/kotlin/app/revanced/patches/hexeditor/ad/patch/HexEditorAdsPatch.kt deleted file mode 100644 index 67bc0940d..000000000 --- a/src/main/kotlin/app/revanced/patches/hexeditor/ad/patch/HexEditorAdsPatch.kt +++ /dev/null @@ -1,39 +0,0 @@ -package app.revanced.patches.hexeditor.ad.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.extensions.replaceInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.hexeditor.ad.annotations.HexEditorAdsCompatibility -import app.revanced.patches.hexeditor.ad.fingerprints.PrimaryAdsFingerprint - -@Patch -@Name("disable-ads") -@Description("Disables ads in HexEditor.") -@HexEditorAdsCompatibility -@Version("0.0.1") -class HexEditorAdsPatch : BytecodePatch( - listOf( - PrimaryAdsFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = PrimaryAdsFingerprint.result!!.mutableMethod - - method.replaceInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/annotations/UnlockProCompatibility.kt deleted file mode 100644 index 649e066b9..000000000 --- a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/annotations/UnlockProCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.iconpackstudio.misc.pro.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("ginlemon.iconpackstudio")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class UnlockProCompatibility diff --git a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt b/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt deleted file mode 100644 index 945ef2ca9..000000000 --- a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/fingerprints/CheckProFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.iconpackstudio.misc.pro.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object CheckProFingerprint : MethodFingerprint( - "Z", - customFingerprint = { it.definingClass.endsWith("IPSPurchaseRepository;")} -) diff --git a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/patch/UnlockProPatch.kt deleted file mode 100644 index a4a2d4f99..000000000 --- a/src/main/kotlin/app/revanced/patches/iconpackstudio/misc/pro/patch/UnlockProPatch.kt +++ /dev/null @@ -1,38 +0,0 @@ -package app.revanced.patches.iconpackstudio.misc.pro.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.iconpackstudio.misc.pro.annotations.UnlockProCompatibility -import app.revanced.patches.iconpackstudio.misc.pro.fingerprints.CheckProFingerprint - -@Patch -@Name("unlock-pro") -@Description("Unlocks all pro features.") -@UnlockProCompatibility -@Version("0.0.1") -class UnlockProPatch : BytecodePatch( - listOf( - CheckProFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = CheckProFingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/moneymanager/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/moneymanager/annotations/UnlockProCompatibility.kt deleted file mode 100644 index 8a46c0e2d..000000000 --- a/src/main/kotlin/app/revanced/patches/moneymanager/annotations/UnlockProCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.moneymanager.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.ithebk.expensemanager")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class UnlockProCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt b/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt deleted file mode 100644 index 9ea14f8ac..000000000 --- a/src/main/kotlin/app/revanced/patches/moneymanager/fingerprints/UnlockProFingerprint.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.moneymanager.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object UnlockProFingerprint : MethodFingerprint( - "Z", - AccessFlags.STATIC or AccessFlags.SYNTHETIC, - parameters = listOf("L"), - opcodes = listOf( - Opcode.IGET_BOOLEAN, - Opcode.RETURN - ), - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("MainActivity;") - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/moneymanager/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/moneymanager/patch/UnlockProPatch.kt deleted file mode 100644 index e857e7140..000000000 --- a/src/main/kotlin/app/revanced/patches/moneymanager/patch/UnlockProPatch.kt +++ /dev/null @@ -1,34 +0,0 @@ -package app.revanced.patches.moneymanager.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.moneymanager.annotations.UnlockProCompatibility -import app.revanced.patches.moneymanager.fingerprints.UnlockProFingerprint - -@Patch -@Name("unlock-pro") -@Description("Unlocks pro features.") -@UnlockProCompatibility -@Version("0.0.1") -class UnlockProPatch : BytecodePatch( - listOf(UnlockProFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - UnlockProFingerprint.result!!.mutableMethod.addInstructions( - 0, - """ - const/4 v0, 0x1 - - return v0 - """ - ) - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/ad/video/annotations/MusicVideoAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/ad/video/annotations/MusicVideoAdsCompatibility.kt deleted file mode 100644 index 314e1597e..000000000 --- a/src/main/kotlin/app/revanced/patches/music/ad/video/annotations/MusicVideoAdsCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.ad.video.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MusicVideoAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/ad/video/fingerprints/ShowMusicVideoAdsConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/ad/video/fingerprints/ShowMusicVideoAdsConstructorFingerprint.kt deleted file mode 100644 index dd60e2026..000000000 --- a/src/main/kotlin/app/revanced/patches/music/ad/video/fingerprints/ShowMusicVideoAdsConstructorFingerprint.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.revanced.patches.music.ad.video.fingerprints -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. -object ShowMusicVideoAdsConstructorFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf( - Opcode.INVOKE_DIRECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.CONST_4, - Opcode.IPUT_BOOLEAN, - Opcode.RETURN_VOID - ) -) diff --git a/src/main/kotlin/app/revanced/patches/music/ad/video/fingerprints/ShowMusicVideoAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/ad/video/fingerprints/ShowMusicVideoAdsFingerprint.kt deleted file mode 100644 index d6d8a138d..000000000 --- a/src/main/kotlin/app/revanced/patches/music/ad/video/fingerprints/ShowMusicVideoAdsFingerprint.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.music.ad.video.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object ShowMusicVideoAdsFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), listOf( - Opcode.IPUT_BOOLEAN, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN_VOID - ) -) diff --git a/src/main/kotlin/app/revanced/patches/music/ad/video/patch/MusicVideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/music/ad/video/patch/MusicVideoAdsPatch.kt index bbf484831..2bcb1e2ec 100644 --- a/src/main/kotlin/app/revanced/patches/music/ad/video/patch/MusicVideoAdsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/ad/video/patch/MusicVideoAdsPatch.kt @@ -5,35 +5,38 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.ad.video.annotations.MusicVideoAdsCompatibility -import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsConstructorFingerprint -import app.revanced.patches.music.ad.video.fingerprints.ShowMusicVideoAdsFingerprint +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.patches.videoads.GeneralVideoAdsPatch @Patch +@DependsOn( + [ + GeneralVideoAdsPatch::class, + MusicIntegrationsPatch::class, + MusicSettingsPatch::class + ] +) @Name("music-video-ads") @Description("Removes ads in the music player.") -@MusicVideoAdsCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") -class MusicVideoAdsPatch : BytecodePatch( - listOf( - ShowMusicVideoAdsConstructorFingerprint - ) -) { +class MusicVideoAdsPatch : BytecodePatch() { override fun execute(context: BytecodeContext): PatchResult { - ShowMusicVideoAdsFingerprint.resolve(context, ShowMusicVideoAdsConstructorFingerprint.result!!.classDef) + val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/settings/MusicSettings;->getShowAds()Z" - val result = ShowMusicVideoAdsFingerprint.result!! + GeneralVideoAdsPatch.injectLegacyAds(INTEGRATIONS_CLASS_DESCRIPTOR) - result.mutableMethod.addInstructions( - result.scanResult.patternScanResult!!.startIndex, """ - const/4 p1, 0x0 - """ - ) + GeneralVideoAdsPatch.injectMainstreamAds(INTEGRATIONS_CLASS_DESCRIPTOR) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/music/audio/codecs/annotations/CodecsUnlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/audio/codecs/annotations/CodecsUnlockCompatibility.kt deleted file mode 100644 index 5fd4bca7f..000000000 --- a/src/main/kotlin/app/revanced/patches/music/audio/codecs/annotations/CodecsUnlockCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.audio.codecs.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CodecsUnlockCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/AllCodecsReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/AllCodecsReferenceFingerprint.kt index 92f047d54..dc49435b2 100644 --- a/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/AllCodecsReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/AllCodecsReferenceFingerprint.kt @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object AllCodecsReferenceFingerprint : MethodFingerprint( "J", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( diff --git a/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/CodecsLockFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/CodecsLockFingerprint.kt index 75189e806..6dd81648d 100644 --- a/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/CodecsLockFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/audio/codecs/fingerprints/CodecsLockFingerprint.kt @@ -1,13 +1,18 @@ package app.revanced.patches.music.audio.codecs.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.impl.MethodFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - +@Name("codec-lock-fingerprint") @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. +@YouTubeMusicCompatibility +@Version("0.0.1") object CodecsLockFingerprint : MethodFingerprint( "L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( Opcode.INVOKE_DIRECT, diff --git a/src/main/kotlin/app/revanced/patches/music/audio/codecs/patch/CodecsUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/music/audio/codecs/patch/CodecsUnlockPatch.kt index 9ff6916b8..329f9a613 100644 --- a/src/main/kotlin/app/revanced/patches/music/audio/codecs/patch/CodecsUnlockPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/audio/codecs/patch/CodecsUnlockPatch.kt @@ -5,20 +5,26 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.toInstruction -import app.revanced.patches.music.audio.codecs.annotations.CodecsUnlockCompatibility +import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.music.audio.codecs.fingerprints.AllCodecsReferenceFingerprint import app.revanced.patches.music.audio.codecs.fingerprints.CodecsLockFingerprint +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.Opcode @Patch +@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class]) @Name("codecs-unlock") @Description("Adds more audio codec options. The new audio codecs usually result in better audio quality.") -@CodecsUnlockCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class CodecsUnlockPatch : BytecodePatch( listOf( @@ -27,8 +33,9 @@ class CodecsUnlockPatch : BytecodePatch( ) { override fun execute(context: BytecodeContext): PatchResult { val codecsLockResult = CodecsLockFingerprint.result!! + val codecsLockMethod = codecsLockResult.mutableMethod - val implementation = codecsLockResult.mutableMethod.implementation!! + val implementation = codecsLockMethod.implementation!! val scanResultStartIndex = codecsLockResult.scanResult.patternScanResult!!.startIndex val instructionIndex = scanResultStartIndex + @@ -46,9 +53,14 @@ class CodecsUnlockPatch : BytecodePatch( .nextMethod(allCodecsResult.scanResult.patternScanResult!!.startIndex) .getMethod() - implementation.replaceInstruction( - instructionIndex, - "invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set;".toInstruction() + codecsLockMethod.addInstructions( + instructionIndex + 2, """ + invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getCodecsUnlock()Z + move-result v7 + if-eqz v7, :mp4a + invoke-static {}, ${allCodecsMethod.definingClass}->${allCodecsMethod.name}()Ljava/util/Set; + move-result-object p4 + """, listOf(ExternalLabel("mp4a", codecsLockMethod.instruction(instructionIndex + 2))) ) return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/annotations/ExclusiveAudioCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/annotations/ExclusiveAudioCompatibility.kt deleted file mode 100644 index a653e57f9..000000000 --- a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/annotations/ExclusiveAudioCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.audio.exclusiveaudio.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ExclusiveAudioCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt index 02eb60adc..e3d3c016d 100644 --- a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/fingerprints/ExclusiveAudioFingerprint.kt @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object ExclusiveAudioFingerprint : MethodFingerprint( "V", diff --git a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/patch/ExclusiveAudioPatch.kt b/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/patch/ExclusiveAudioPatch.kt index d679e8702..9629aacd8 100644 --- a/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/patch/ExclusiveAudioPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/audio/exclusiveaudio/patch/ExclusiveAudioPatch.kt @@ -6,17 +6,17 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.audio.exclusiveaudio.annotations.ExclusiveAudioCompatibility import app.revanced.patches.music.audio.exclusiveaudio.fingerprints.AudioOnlyEnablerFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility @Patch @Name("exclusive-audio-playback") @Description("Enables the option to play music without video.") -@ExclusiveAudioCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class ExclusiveAudioPatch : BytecodePatch( listOf( diff --git a/src/main/kotlin/app/revanced/patches/music/layout/blacknavbar/bytecode/patch/BlackNavbarPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/blacknavbar/bytecode/patch/BlackNavbarPatch.kt new file mode 100644 index 000000000..794d56d96 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/blacknavbar/bytecode/patch/BlackNavbarPatch.kt @@ -0,0 +1,84 @@ +package app.revanced.patches.music.layout.blacknavbar.bytecode.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.Instruction11x +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Patch +@DependsOn( + [ + MusicIntegrationsPatch::class, + MusicSettingsPatch::class, + ResourceMappingPatch::class + ] +) +@Name("black-navbar") +@Description("Sets the navigation bar color to black.") +@YouTubeMusicCompatibility +@Version("0.0.1") +class BlackNavbarPatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "ytm_color_grey_12" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // blacknavbar + val insertIndex = index - 1 + val insertIndex2 = index + 2 + val invokeInstruction = instructions.elementAt(insertIndex) + val invokeInstruction2 = instructions.elementAt(insertIndex2) + if (invokeInstruction.opcode != Opcode.MOVE_RESULT_OBJECT) return@forEachIndexed + + val register1 = (instructions.elementAt(index) as Instruction31i).registerA + val register2 = (invokeInstruction2 as Instruction11x).registerA + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + mutableMethod.addInstructions( + index + 3, """ + invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getBlackNavbar()Z + move-result v$register1 + if-eqz v$register1, :default + const/high16 v$register2, -0x1000000 + """, listOf(ExternalLabel("default", mutableMethod.instruction(index + 3))) + ) + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/patch/CustomBrandingMusicPatch_Red.kt b/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/patch/CustomBrandingMusicPatch_Red.kt new file mode 100644 index 000000000..89481d4de --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/patch/CustomBrandingMusicPatch_Red.kt @@ -0,0 +1,111 @@ +package app.revanced.patches.music.layout.branding.icon.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch +@Name("custom-branding-music-red") +@Description("Changes the YouTube Music launcher icon to your choice (defaults to ReVanced Red).") +@YouTubeMusicCompatibility +@Version("0.0.1") +class CustomBrandingMusicPatch_Red : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + val classLoader = this.javaClass.classLoader + val resDirectory = context["res"] + if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.") + + // App Icon + val AppiconNames = arrayOf( + "adaptiveproduct_youtube_music_background_color_108", + "adaptiveproduct_youtube_music_foreground_color_108", + "ic_launcher_release" + ) + + mapOf( + "xxxhdpi" to 192, + "xxhdpi" to 144, + "xhdpi" to 96, + "hdpi" to 72, + "mdpi" to 48 + ).forEach { (iconDirectory, size) -> + AppiconNames.forEach iconLoop@{ iconName -> + Files.copy( + classLoader.getResourceAsStream("music/branding/red/launchericon/$size/$iconName.png")!!, + resDirectory.resolve("mipmap-$iconDirectory").resolve("$iconName.png").toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + // Other Resource + val drawables1 = "drawable-hdpi" to arrayOf( + "action_bar_logo", + "action_bar_logo_release", + "record" + ) + + val drawables2 = "drawable-large-hdpi" to arrayOf( + "record" + ) + + val drawables3 = "drawable-large-mdpi" to arrayOf( + "record" + ) + + val drawables4 = "drawable-large-xhdpi" to arrayOf( + "record" + ) + + val drawables5 = "drawable-mdpi" to arrayOf( + "action_bar_logo", + "record" + ) + + val drawables6 = "drawable-xhdpi" to arrayOf( + "action_bar_logo", + "record" + ) + + val drawables7 = "drawable-xlarge-hdpi" to arrayOf( + "record" + ) + + val drawables8 = "drawable-xlarge-mdpi" to arrayOf( + "record" + ) + + val drawables9 = "drawable-xxhdpi" to arrayOf( + "action_bar_logo", + "record" + ) + + val drawables10 = "drawable-xxxhdpi" to arrayOf( + "action_bar_logo" + ) + + val pngResources = arrayOf(drawables1, drawables2, drawables3, drawables4, drawables5, drawables6, drawables7, drawables8, drawables9, drawables10) + + pngResources.forEach { (path, resourceNames) -> + resourceNames.forEach { name -> + val relativePath = "$path/$name.png" + + Files.copy( + classLoader.getResourceAsStream("music/branding/red/resource/$relativePath")!!, + context["res"].resolve(relativePath).toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + return PatchResultSuccess() + } + +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/patch/CustomBrandingMusicPatch_Revancify.kt b/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/patch/CustomBrandingMusicPatch_Revancify.kt new file mode 100644 index 000000000..f0ca2c638 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/branding/icon/patch/CustomBrandingMusicPatch_Revancify.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.music.layout.branding.icon.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.* +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch(false) +@Name("custom-branding-music-revancify") +@Description("Changes the YouTube Music launcher icon to your choice (Revancify).") +@YouTubeMusicCompatibility +@Version("0.0.1") +class CustomBrandingMusicPatch_Revancify : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + val classLoader = this.javaClass.classLoader + val resDirectory = context["res"] + if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.") + + // App Icon + val AppiconNames = arrayOf( + "adaptiveproduct_youtube_music_background_color_108", + "adaptiveproduct_youtube_music_foreground_color_108", + "ic_launcher_release" + ) + + mapOf( + "xxxhdpi" to 192, + "xxhdpi" to 144, + "xhdpi" to 96, + "hdpi" to 72, + "mdpi" to 48 + ).forEach { (iconDirectory, size) -> + AppiconNames.forEach iconLoop@{ iconName -> + Files.copy( + classLoader.getResourceAsStream("music/branding/revancify/launchericon/$size/$iconName.png")!!, + resDirectory.resolve("mipmap-$iconDirectory").resolve("$iconName.png").toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + // MonoChrome Icon + arrayOf("drawable" to arrayOf("ic_app_icons_themed_youtube_music")).forEach { (path, resourceNames) -> + resourceNames.forEach { name -> + val relativePath = "$path/$name.xml" + + Files.copy( + classLoader.getResourceAsStream("music/branding/revancify/monochromeicon/$relativePath")!!, + context["res"].resolve(relativePath).toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + return PatchResultSuccess() + } + +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/castbutton/fingerprints/HideCastButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/castbutton/fingerprints/HideCastButtonFingerprint.kt new file mode 100644 index 000000000..bdd609cd4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/castbutton/fingerprints/HideCastButtonFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.music.layout.castbutton.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.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("hide-castbutton-signature") +@YouTubeMusicCompatibility +@Version("0.0.1") +object HideCastButtonFingerprint : MethodFingerprint ( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("I"), null ,null, null +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/castbutton/fingerprints/HideCastButtonParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/castbutton/fingerprints/HideCastButtonParentFingerprint.kt new file mode 100644 index 000000000..e08a0bc94 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/castbutton/fingerprints/HideCastButtonParentFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.music.layout.castbutton.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.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("hide-castbutton-parent-signature") +@YouTubeMusicCompatibility +@Version("0.0.1") +object HideCastButtonParentFingerprint : MethodFingerprint ( + "Z", AccessFlags.PRIVATE or AccessFlags.FINAL, + strings = listOf("MediaRouteButton") +) diff --git a/src/main/kotlin/app/revanced/patches/music/layout/castbutton/patch/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/castbutton/patch/HideCastButtonPatch.kt new file mode 100644 index 000000000..2b61b7e8b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/castbutton/patch/HideCastButtonPatch.kt @@ -0,0 +1,46 @@ +package app.revanced.patches.music.layout.castbutton.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.music.layout.castbutton.fingerprints.HideCastButtonFingerprint +import app.revanced.patches.music.layout.castbutton.fingerprints.HideCastButtonParentFingerprint +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility + +@Patch +@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class]) +@Name("hide-music-cast-button") +@Description("Hides the cast button in the video player and header") +@YouTubeMusicCompatibility +@Version("0.0.1") +class HideWatermarkPatch : BytecodePatch( + listOf( + HideCastButtonParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + HideCastButtonFingerprint.resolve(context, HideCastButtonParentFingerprint.result!!.classDef) + val result = HideCastButtonFingerprint.result + ?: return PatchResultError("Required parent method could not be found.") + + result.mutableMethod.addInstructions( + 0, """ + invoke-static {p1}, Lapp/revanced/integrations/settings/MusicSettings;->getCastButtonOverrideV2(I)I + move-result p1 + """ + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/compactheader/annotations/CompactHeaderCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/layout/compactheader/annotations/CompactHeaderCompatibility.kt deleted file mode 100644 index a54a37194..000000000 --- a/src/main/kotlin/app/revanced/patches/music/layout/compactheader/annotations/CompactHeaderCompatibility.kt +++ /dev/null @@ -1,29 +0,0 @@ -package app.revanced.patches.music.layout.compactheader.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CompactHeaderCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/layout/compactheader/fingerprints/CompactHeaderConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/compactheader/fingerprints/CompactHeaderConstructorFingerprint.kt index 661c138d7..c37477df8 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/compactheader/fingerprints/CompactHeaderConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/compactheader/fingerprints/CompactHeaderConstructorFingerprint.kt @@ -1,10 +1,16 @@ package app.revanced.patches.music.layout.compactheader.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.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@Name("compact-header-constructor-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") object CompactHeaderConstructorFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L"), listOf( Opcode.INVOKE_DIRECT, diff --git a/src/main/kotlin/app/revanced/patches/music/layout/compactheader/patch/CompactHeaderPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/compactheader/patch/CompactHeaderPatch.kt index 879dfa0c0..4435446ab 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/compactheader/patch/CompactHeaderPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/compactheader/patch/CompactHeaderPatch.kt @@ -5,18 +5,22 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.layout.compactheader.annotations.CompactHeaderCompatibility import app.revanced.patches.music.layout.compactheader.fingerprints.CompactHeaderConstructorFingerprint +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.builder.instruction.BuilderInstruction11x -@Patch(false) +@Patch +@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class]) @Name("compact-header") @Description("Hides the music category bar at the top of the homepage.") -@CompactHeaderCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class CompactHeaderPatch : BytecodePatch( listOf( @@ -31,7 +35,8 @@ class CompactHeaderPatch : BytecodePatch( val register = (method.implementation!!.instructions[insertIndex - 1] as BuilderInstruction11x).registerA method.addInstructions( insertIndex, """ - const/16 v2, 0x8 + invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getCompactHeader()I + move-result v2 invoke-virtual {v${register}, v2}, Landroid/view/View;->setVisibility(I)V """ ) diff --git a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt deleted file mode 100644 index b5ec0f5b6..000000000 --- a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.layout.minimizedplayback.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MinimizedPlaybackCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt index eb3d28a08..6a4f9b18c 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt @@ -1,10 +1,16 @@ package app.revanced.patches.music.layout.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.impl.MethodFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@Name("minimized-playback-manager-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") object MinimizedPlaybackManagerFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, diff --git a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt index dcfdb9f05..7eef65dbd 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayback/patch/MinimizedPlaybackPatch.kt @@ -4,18 +4,22 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.layout.minimizedplayback.annotations.MinimizedPlaybackCompatibility +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.music.layout.minimizedplayback.fingerprints.MinimizedPlaybackManagerFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.MethodReference @Patch @Name("minimized-playback-music") @Description("Enables minimized playback on Kids music.") -@MinimizedPlaybackCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class MinimizedPlaybackPatch : BytecodePatch( listOf( @@ -23,10 +27,8 @@ class MinimizedPlaybackPatch : BytecodePatch( ) ) { override fun execute(context: BytecodeContext): PatchResult { - MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstructions( - 0, """ - return-void - """ + MinimizedPlaybackManagerFingerprint.result!!.mutableMethod.addInstruction( + 0, "return-void" ) return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayer/fingerprints/MinimizedPlayerFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayer/fingerprints/MinimizedPlayerFingerprint.kt new file mode 100644 index 000000000..d4e7e0ed1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayer/fingerprints/MinimizedPlayerFingerprint.kt @@ -0,0 +1,28 @@ +package app.revanced.patches.music.layout.minimizedplayer.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.shared.annotation.YouTubeCompatibility +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("minimized-player-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") +object MinimizedPlayerFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L"), listOf( + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.CONST_4, + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.INVOKE_VIRTUAL + ), + strings = listOf("w_st") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayer/patch/MinimizedPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayer/patch/MinimizedPlayerPatch.kt new file mode 100644 index 000000000..b490b040b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/minimizedplayer/patch/MinimizedPlayerPatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.music.layout.minimizedplayer.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.music.layout.minimizedplayer.fingerprints.MinimizedPlayerFingerprint +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Patch +@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class]) +@Name("minimized-player") +@Description("Permanently keep player minimized even if another track is played.") +@YouTubeMusicCompatibility +@Version("0.0.1") +class MinimizedPlayerPatch : BytecodePatch( + listOf( + MinimizedPlayerFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + val result = MinimizedPlayerFingerprint.result!! + val method = result.mutableMethod + val index = result.scanResult.patternScanResult!!.endIndex + val register = (method.implementation!!.instructions[index - 1] as OneRegisterInstruction).registerA - 1 + val jumpInstruction = method.implementation!!.instructions[index + 1] as Instruction + + method.addInstructions( + index, """ + invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getEnforceMinimizedPlayer()Z + move-result v$register + if-nez v$register, :enforce + """, listOf(ExternalLabel("enforce", jumpInstruction)) + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/fingerprints/MiniplayerColorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/fingerprints/MiniplayerColorFingerprint.kt new file mode 100644 index 000000000..b2e39bc54 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/fingerprints/MiniplayerColorFingerprint.kt @@ -0,0 +1,20 @@ +package app.revanced.patches.music.layout.miniplayercolor.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.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("miniplayer-color-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") +object MiniplayerColorFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "J"), listOf( + Opcode.INVOKE_DIRECT, + Opcode.IPUT_OBJECT, + Opcode.RETURN_VOID + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/fingerprints/MiniplayerColorParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/fingerprints/MiniplayerColorParentFingerprint.kt new file mode 100644 index 000000000..3df33b9e3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/fingerprints/MiniplayerColorParentFingerprint.kt @@ -0,0 +1,33 @@ +package app.revanced.patches.music.layout.miniplayercolor.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.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +@Name("miniplayer-color-hook-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") +object MiniplayerColorParentFingerprint : MethodFingerprint( + "V", + AccessFlags.PRIVATE or AccessFlags.FINAL, + null, + listOf( + Opcode.IGET, + Opcode.IGET, + Opcode.CONST_WIDE_16, + Opcode.IF_EQ, + Opcode.IPUT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET, + Opcode.IGET, + Opcode.IF_EQ, + Opcode.IPUT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/patch/MiniplayerColorPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/patch/MiniplayerColorPatch.kt new file mode 100644 index 000000000..7cbea0be3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/patch/MiniplayerColorPatch.kt @@ -0,0 +1,99 @@ +package app.revanced.patches.music.layout.miniplayercolor.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.removeInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorFingerprint +import app.revanced.patches.music.layout.miniplayercolor.fingerprints.MiniplayerColorParentFingerprint +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference + +@Patch +@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class]) +@Name("miniplayer-color") +@Description("Matches the fullscreen player color with the minimized one.") +@YouTubeMusicCompatibility +@Version("0.0.1") +class MiniplayerColorPatch : BytecodePatch( + listOf( + MiniplayerColorFingerprint, MiniplayerColorParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + val miniplayerColorParentResult = MiniplayerColorParentFingerprint.result!! + val miniplayerColorParentMethod = miniplayerColorParentResult.mutableMethod + + MiniplayerColorFingerprint.resolve(context, miniplayerColorParentResult.classDef) + val miniplayerColorResult = MiniplayerColorFingerprint.result!! + val miniplayerColorMethod = miniplayerColorResult.mutableMethod + val insertIndex = miniplayerColorResult.scanResult.patternScanResult!!.startIndex + 1 + val jumpInstruction = miniplayerColorMethod.implementation!!.instructions[insertIndex] as Instruction + + val Reference_A_1 = + miniplayerColorParentMethod.let { method -> + (method.implementation!!.instructions.elementAt(4) as ReferenceInstruction).reference as FieldReference + } + val Reference_A_2 = + miniplayerColorParentMethod.let { method -> + (method.implementation!!.instructions.elementAt(5) as ReferenceInstruction).reference as FieldReference + } + val Reference_A_3 = + miniplayerColorParentMethod.let { method -> + (method.implementation!!.instructions.elementAt(6) as ReferenceInstruction).reference as MethodReference + } + val Reference_B_1 = + miniplayerColorParentMethod.let { method -> + (method.implementation!!.instructions.elementAt(10) as ReferenceInstruction).reference as FieldReference + } + val Reference_B_2 = + miniplayerColorParentMethod.let { method -> + (method.implementation!!.instructions.elementAt(11) as ReferenceInstruction).reference as FieldReference + } + val Reference_B_3 = + miniplayerColorParentMethod.let { method -> + (method.implementation!!.instructions.elementAt(12) as ReferenceInstruction).reference as MethodReference + } + + miniplayerColorMethod.addInstructions( + insertIndex, """ + invoke-static {}, Lapp/revanced/integrations/settings/MusicSettings;->getMiniPlayerColor()Z + move-result v2 + if-eqz v2, :off + iget v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_1.name}:${Reference_A_1.type} + if-eq v0, v2, :abswitch + iput v2, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_1.name}:${Reference_A_1.type} + iget-object v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_A_2.name}:${Reference_A_2.type} + invoke-virtual {v0, v2, p2, p3}, $Reference_A_3 + :abswitch + iget v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_B_1.name}:${Reference_B_1.type} + if-eq v0, v1, :exit + iput v1, p0, ${miniplayerColorResult.classDef.type}->${Reference_B_1.name}:${Reference_B_1.type} + iget-object v0, p0, ${miniplayerColorResult.classDef.type}->${Reference_B_2.name}:${Reference_B_2.type} + invoke-virtual {v0, v1, p2, p3}, $Reference_B_3 + goto :exit + :off + invoke-direct {p0}, ${miniplayerColorResult.classDef.type}->${miniplayerColorParentResult.mutableMethod.name}()V + """, listOf(ExternalLabel("exit", jumpInstruction)) + ) + + miniplayerColorMethod.removeInstruction(insertIndex - 1) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/layout/premium/annotations/HideGetPremiumCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/layout/premium/annotations/HideGetPremiumCompatibility.kt deleted file mode 100644 index f2089df2a..000000000 --- a/src/main/kotlin/app/revanced/patches/music/layout/premium/annotations/HideGetPremiumCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.layout.premium.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideGetPremiumCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt index 5b89674cc..d6b9d74b6 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumFingerprint.kt @@ -1,10 +1,16 @@ package app.revanced.patches.music.layout.premium.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.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@Name("hide-get-premium-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") object HideGetPremiumFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( Opcode.IF_NEZ, diff --git a/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumParentFingerprint.kt index d91ff64a4..629bd6d62 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/premium/fingerprints/HideGetPremiumParentFingerprint.kt @@ -1,10 +1,16 @@ package app.revanced.patches.music.layout.premium.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.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@Name("hide-get-premium-parent-fingerprint") +@YouTubeMusicCompatibility +@Version("0.0.1") object HideGetPremiumParentFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( Opcode.IGET_BOOLEAN, diff --git a/src/main/kotlin/app/revanced/patches/music/layout/premium/patch/HideGetPremiumPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/premium/patch/HideGetPremiumPatch.kt index 727ff9dd9..0f41c286f 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/premium/patch/HideGetPremiumPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/premium/patch/HideGetPremiumPatch.kt @@ -7,18 +7,18 @@ import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.layout.premium.annotations.HideGetPremiumCompatibility import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumFingerprint import app.revanced.patches.music.layout.premium.fingerprints.HideGetPremiumParentFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility @Patch @Name("hide-get-premium") @Description("Removes all \"Get Premium\" evidences from the avatar menu.") -@HideGetPremiumCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class HideGetPremiumPatch : BytecodePatch( listOf( diff --git a/src/main/kotlin/app/revanced/patches/music/layout/tabletmode/bytecode/patch/TabletModePatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/tabletmode/bytecode/patch/TabletModePatch.kt new file mode 100644 index 000000000..44f4b595b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/layout/tabletmode/bytecode/patch/TabletModePatch.kt @@ -0,0 +1,75 @@ +package app.revanced.patches.music.layout.tabletmode.bytecode.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Patch +@DependsOn( + [ + MusicIntegrationsPatch::class, + MusicSettingsPatch::class, + ResourceMappingPatch::class + ] +) +@Name("tablet-mode") +@Description("Unlocks landscape mode.") +@YouTubeMusicCompatibility +@Version("0.0.1") +class TabletModePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "is_tablet" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // tablet + val insertIndex = index - 2 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + mutableMethod.addInstructions( + index + 3, """ + invoke-static {p0}, Lapp/revanced/integrations/settings/MusicSettings;->getTabletMode(Z)Z + move-result p0 + """ + ) + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/annotations/RemoveTasteBuilderCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/annotations/RemoveTasteBuilderCompatibility.kt deleted file mode 100644 index c51a2f11d..000000000 --- a/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/annotations/RemoveTasteBuilderCompatibility.kt +++ /dev/null @@ -1,32 +0,0 @@ -package app.revanced.patches.music.layout.tastebuilder.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -/** - * -- Note 2022-08-05 -- - * Since 5.17.xx the tastebuilder component is dismissible, so this patch is less useful - * also it is partly litho now - */ -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class RemoveTasteBuilderCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/fingerprints/TasteBuilderConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/fingerprints/TasteBuilderConstructorFingerprint.kt index e72193c6f..a14566233 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/fingerprints/TasteBuilderConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/fingerprints/TasteBuilderConstructorFingerprint.kt @@ -1,13 +1,18 @@ package app.revanced.patches.music.layout.tastebuilder.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.impl.MethodFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - +@Name("taste-builder-constructor-fingerprint") @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. +@YouTubeMusicCompatibility +@Version("0.0.1") object TasteBuilderConstructorFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L"), listOf( Opcode.INVOKE_DIRECT, diff --git a/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/patch/RemoveTasteBuilderPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/patch/RemoveTasteBuilderPatch.kt index d3b61a3f7..b19e78a48 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/patch/RemoveTasteBuilderPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/tastebuilder/patch/RemoveTasteBuilderPatch.kt @@ -5,18 +5,18 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.layout.tastebuilder.annotations.RemoveTasteBuilderCompatibility import app.revanced.patches.music.layout.tastebuilder.fingerprints.TasteBuilderConstructorFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.iface.instruction.formats.Instruction22c @Patch @Name("tasteBuilder-remover") @Description("Removes the \"Tell us which artists you like\" card from the home screen.") -@RemoveTasteBuilderCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class RemoveTasteBuilderPatch : BytecodePatch( listOf( diff --git a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/annotations/RemoveUpgradeButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/annotations/RemoveUpgradeButtonCompatibility.kt deleted file mode 100644 index b949a4a5d..000000000 --- a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/annotations/RemoveUpgradeButtonCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.layout.upgradebutton.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class RemoveUpgradeButtonCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt index e62225b25..c04e8da90 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/fingerprints/PivotBarConstructorFingerprint.kt @@ -1,13 +1,18 @@ package app.revanced.patches.music.layout.upgradebutton.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.impl.MethodFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - +@Name("pivot-bar-constructor-fingerprint") @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. +@YouTubeMusicCompatibility +@Version("0.0.1") object PivotBarConstructorFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, diff --git a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/patch/RemoveUpgradeButtonPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/patch/RemoveUpgradeButtonPatch.kt index 9bf8ad011..f206e1543 100644 --- a/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/patch/RemoveUpgradeButtonPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/patch/RemoveUpgradeButtonPatch.kt @@ -5,23 +5,23 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.smali.toInstructions -import app.revanced.patches.music.layout.upgradebutton.annotations.RemoveUpgradeButtonCompatibility import app.revanced.patches.music.layout.upgradebutton.fingerprints.PivotBarConstructorFingerprint -import org.jf.dexlib2.Opcode +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.builder.instruction.BuilderInstruction22t import org.jf.dexlib2.iface.instruction.formats.Instruction22c import org.jf.dexlib2.iface.instruction.formats.Instruction35c +import org.jf.dexlib2.Opcode @Patch @Name("upgrade-button-remover") @Description("Removes the upgrade tab from the pivot bar.") -@RemoveUpgradeButtonCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class RemoveUpgradeButtonPatch : BytecodePatch( listOf( diff --git a/src/main/kotlin/app/revanced/patches/music/misc/clientspoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/clientspoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt new file mode 100644 index 000000000..4f6973d1e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/clientspoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.music.misc.clientspoof.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object UserAgentHeaderBuilderFingerprint : MethodFingerprint( + parameters = listOf("L"), + opcodes = listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL, Opcode.CONST_16), + strings = listOf("(Linux; U; Android ") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/patch/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/clientspoof/patch/ClientSpoofMusicPatch.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/patch/ClientSpoofPatch.kt rename to src/main/kotlin/app/revanced/patches/music/misc/clientspoof/patch/ClientSpoofMusicPatch.kt index 0b6a1ebe9..4e10e39ff 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/patch/ClientSpoofPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/clientspoof/patch/ClientSpoofMusicPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.fix.spoof.patch +package app.revanced.patches.music.misc.clientspoof.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -6,30 +6,31 @@ import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.fix.spoof.annotations.ClientSpoofCompatibility -import app.revanced.patches.youtube.misc.fix.spoof.fingerprints.UserAgentHeaderBuilderFingerprint +import app.revanced.patches.music.misc.clientspoof.fingerprints.UserAgentHeaderBuilderFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction @Patch -@Name("client-spoof") -@Description("Spoofs the YouTube or Vanced client to prevent playback issues.") -@ClientSpoofCompatibility +@Name("client-spoof-music") +@Description("Spoofs the YouTube Music client.") +@YouTubeMusicCompatibility @Version("0.0.1") -class ClientSpoofPatch : BytecodePatch( +class ClientSpoofMusicPatch : BytecodePatch( listOf(UserAgentHeaderBuilderFingerprint) ) { override fun execute(context: BytecodeContext): PatchResult { + val result = UserAgentHeaderBuilderFingerprint.result!! val method = result.mutableMethod - val insertIndex = result.scanResult.patternScanResult!!.endIndex + val insertIndex = result.scanResult.patternScanResult!!.endIndex - 1 val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD - val originalPackageName = "com.google.android.youtube" + val originalPackageName = "com.google.android.apps.youtube.music" method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"") return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/InitFingerprint.kt new file mode 100644 index 000000000..1a8f5014a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/integrations/fingerprints/InitFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.music.misc.integrations.fingerprints + +import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint + +object InitFingerprint : IntegrationsFingerprint( + strings = listOf("YouTubeMusic", "activity") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/misc/integrations/patch/MusicIntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/integrations/patch/MusicIntegrationsPatch.kt new file mode 100644 index 000000000..32460a7f8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/integrations/patch/MusicIntegrationsPatch.kt @@ -0,0 +1,13 @@ +package app.revanced.patches.music.misc.integrations.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patches.music.misc.integrations.fingerprints.InitFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch + +@Name("music-integrations") +@YouTubeMusicCompatibility +class MusicIntegrationsPatch : AbstractIntegrationsPatch( + "Lapp/revanced/integrations/settings/MusicSettings;", + listOf(InitFingerprint), +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/annotations/MusicMicroGPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/annotations/MusicMicroGPatchCompatibility.kt deleted file mode 100644 index a4636a23e..000000000 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/annotations/MusicMicroGPatchCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.misc.microg.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MusicMicroGPatchCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastContextFetchFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastContextFetchFingerprint.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastContextFetchFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastContextFetchFingerprint.kt index 04d0430f0..3fdaec70c 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastContextFetchFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastContextFetchFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.music.misc.microg.fingerprints - +package app.revanced.patches.music.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastDynamiteModuleFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastDynamiteModuleFingerprint.kt similarity index 76% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastDynamiteModuleFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastDynamiteModuleFingerprint.kt index a4d39a8dd..5dff4dd5f 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastDynamiteModuleFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastDynamiteModuleFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.music.misc.microg.fingerprints - +package app.revanced.patches.music.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastDynamiteModuleV2Fingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastDynamiteModuleV2Fingerprint.kt similarity index 73% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastDynamiteModuleV2Fingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastDynamiteModuleV2Fingerprint.kt index 8939593cd..686e0fd7e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastDynamiteModuleV2Fingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/CastDynamiteModuleV2Fingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints - +package app.revanced.patches.music.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/GooglePlayUtilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/GooglePlayUtilityFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/GooglePlayUtilityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/GooglePlayUtilityFingerprint.kt index eaefab9b2..dc1fe1631 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/GooglePlayUtilityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/GooglePlayUtilityFingerprint.kt @@ -1,18 +1,18 @@ -package app.revanced.patches.music.misc.microg.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object GooglePlayUtilityFingerprint : MethodFingerprint( - "I", - AccessFlags.PUBLIC or AccessFlags.STATIC, - listOf("L", "I"), - strings = listOf( - "This should never happen.", - "MetadataValueReader", - "GooglePlayServicesUtil", - "com.android.vending", - "android.hardware.type.embedded" - ) +package app.revanced.patches.music.misc.microg.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object GooglePlayUtilityFingerprint : MethodFingerprint( + "I", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L", "I"), + strings = listOf( + "This should never happen.", + "MetadataValueReader", + "GooglePlayServicesUtil", + "com.android.vending", + "android.hardware.type.embedded" + ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/PrimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/PrimeFingerprint.kt similarity index 74% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/PrimeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/PrimeFingerprint.kt index 04fcf8613..cc4719d46 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/PrimeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/PrimeFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints - +package app.revanced.patches.music.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/ServiceCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/ServiceCheckFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/ServiceCheckFingerprint.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/ServiceCheckFingerprint.kt index dd0833144..4cea72dd6 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/ServiceCheckFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/fingerprints/ServiceCheckFingerprint.kt @@ -1,15 +1,14 @@ -package app.revanced.patches.music.misc.microg.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - - -@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. -object ServiceCheckFingerprint : MethodFingerprint( - "V", - AccessFlags.PUBLIC or AccessFlags.STATIC, - listOf("L", "I"), - strings = listOf("Google Play Services not available") -) +package app.revanced.patches.music.misc.microg.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. +object ServiceCheckFingerprint : MethodFingerprint( + "V", + AccessFlags.PUBLIC or AccessFlags.STATIC, + listOf("L", "I"), + strings = listOf("Google Play Services not available") +) diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/patch/bytecode/MusicMicroGBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/patch/MusicMicroGBytecodePatch.kt similarity index 64% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/patch/bytecode/MusicMicroGBytecodePatch.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/patch/MusicMicroGBytecodePatch.kt index 7fca848f8..857a13709 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/patch/bytecode/MusicMicroGBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/bytecode/patch/MusicMicroGBytecodePatch.kt @@ -1,65 +1,79 @@ -package app.revanced.patches.music.misc.microg.patch.bytecode - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility -import app.revanced.patches.music.misc.microg.fingerprints.* -import app.revanced.patches.music.misc.microg.patch.resource.MusicMicroGResourcePatch -import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME -import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants -import app.revanced.util.microg.MicroGBytecodeHelper - -@Patch -@DependsOn([MusicMicroGResourcePatch::class]) -@Name("music-microg-support") -@Description("Allows YouTube Music ReVanced to run without root and under a different package name.") -@MusicMicroGPatchCompatibility -@Version("0.0.2") -class MusicMicroGBytecodePatch : BytecodePatch( - listOf( - ServiceCheckFingerprint, - GooglePlayUtilityFingerprint, - CastDynamiteModuleFingerprint, - CastDynamiteModuleV2Fingerprint, - CastContextFetchFingerprint, - PrimeFingerprint, - ) -) { - // NOTE: the previous patch also replaced the following strings, but it seems like they are not needed: - // - "com.google.android.gms.chimera.GmsIntentOperationService", - // - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks", - // - "com.google.android.gms.phenotype.internal.IPhenotypeService", - // - "com.google.android.gms.phenotype.PACKAGE_NAME", - // - "com.google.android.gms.phenotype.UPDATE", - // - "com.google.android.gms.phenotype", - override fun execute(context: BytecodeContext) = - // apply common microG patch - MicroGBytecodeHelper.patchBytecode( - context, - arrayOf( - MicroGBytecodeHelper.packageNameTransform( - Constants.PACKAGE_NAME, - Constants.REVANCED_PACKAGE_NAME - ) - ), - MicroGBytecodeHelper.PrimeMethodTransformationData( - PrimeFingerprint, - MUSIC_PACKAGE_NAME, - REVANCED_MUSIC_PACKAGE_NAME - ), - listOf( - ServiceCheckFingerprint, - GooglePlayUtilityFingerprint, - CastDynamiteModuleFingerprint, - CastDynamiteModuleV2Fingerprint, - CastContextFetchFingerprint - ) - ).let { PatchResultSuccess() } -} +package app.revanced.patches.music.misc.microg.bytecode.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.music.misc.clientspoof.patch.ClientSpoofMusicPatch +import app.revanced.patches.music.misc.microg.bytecode.fingerprints.* +import app.revanced.patches.music.misc.microg.resource.patch.MusicMicroGResourcePatch +import app.revanced.patches.music.misc.microg.shared.Constants.YOUTUBE_PACKAGE_NAME +import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.microg.MicroGBytecodeHelper + +@Patch +@DependsOn( + [ + ClientSpoofMusicPatch::class, + MusicMicroGResourcePatch::class, + PatchOptions::class + ] +) +@Name("music-microg-support") +@Description("Allows YouTube Music ReVanced to run without root and under a different package name.") +@YouTubeMusicCompatibility +@Version("0.0.2") +class MusicMicroGBytecodePatch : BytecodePatch( + listOf( + ServiceCheckFingerprint, + GooglePlayUtilityFingerprint, + CastDynamiteModuleFingerprint, + CastDynamiteModuleV2Fingerprint, + CastContextFetchFingerprint, + PrimeFingerprint, + ) +) { + // NOTE: the previous patch also replaced the following strings, but it seems like they are not needed: + // - "com.google.android.gms.chimera.GmsIntentOperationService", + // - "com.google.android.gms.phenotype.internal.IPhenotypeCallbacks", + // - "com.google.android.gms.phenotype.internal.IPhenotypeService", + // - "com.google.android.gms.phenotype.PACKAGE_NAME", + // - "com.google.android.gms.phenotype.UPDATE", + // - "com.google.android.gms.phenotype", + override fun execute(context: BytecodeContext): PatchResult { + var YouTubePackageName = PatchOptions.YouTube_PackageName + var MusicPackageName = PatchOptions.Music_PackageName + + // apply common microG patch + MicroGBytecodeHelper.patchBytecode( + context, + arrayOf( + MicroGBytecodeHelper.packageNameTransform( + YOUTUBE_PACKAGE_NAME, + "$YouTubePackageName" + ) + ), + MicroGBytecodeHelper.PrimeMethodTransformationData( + PrimeFingerprint, + MUSIC_PACKAGE_NAME, + "$MusicPackageName" + ), + listOf( + ServiceCheckFingerprint, + GooglePlayUtilityFingerprint, + CastDynamiteModuleFingerprint, + CastDynamiteModuleV2Fingerprint, + CastContextFetchFingerprint + ) + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/patch/resource/MusicMicroGResourcePatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/resource/patch/MusicMicroGResourcePatch.kt similarity index 69% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/patch/resource/MusicMicroGResourcePatch.kt rename to src/main/kotlin/app/revanced/patches/music/misc/microg/resource/patch/MusicMicroGResourcePatch.kt index 19daba368..42b874ae2 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/patch/resource/MusicMicroGResourcePatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/resource/patch/MusicMicroGResourcePatch.kt @@ -1,33 +1,39 @@ -package app.revanced.patches.music.misc.microg.patch.resource +package app.revanced.patches.music.misc.microg.resource.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patches.music.misc.microg.annotations.MusicMicroGPatchCompatibility import app.revanced.patches.music.misc.microg.shared.Constants.MUSIC_PACKAGE_NAME -import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_APP_NAME -import app.revanced.patches.music.misc.microg.shared.Constants.REVANCED_MUSIC_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_PACKAGE_NAME import app.revanced.patches.music.misc.microg.shared.Constants.SPOOFED_PACKAGE_SIGNATURE -import app.revanced.util.microg.MicroGManifestHelper -import app.revanced.util.microg.MicroGResourceHelper +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.microg.MicroGManifestHelper +import app.revanced.shared.util.microg.MicroGResourceHelper @Name("music-microg-resource-patch") @Description("Resource patch to allow YouTube Music ReVanced to run without root and under a different package name.") -@MusicMicroGPatchCompatibility +@DependsOn( + [ + PatchOptions::class + ] +) +@YouTubeMusicCompatibility @Version("0.0.2") class MusicMicroGResourcePatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { + var MusicPackageName = PatchOptions.Music_PackageName + // update manifest MicroGResourceHelper.patchManifest( context, MUSIC_PACKAGE_NAME, - REVANCED_MUSIC_PACKAGE_NAME, - REVANCED_MUSIC_APP_NAME + "$MusicPackageName" ) // add metadata to the manifest diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/shared/Constants.kt b/src/main/kotlin/app/revanced/patches/music/misc/microg/shared/Constants.kt index a7405cc4e..35d8cd35a 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/shared/Constants.kt +++ b/src/main/kotlin/app/revanced/patches/music/misc/microg/shared/Constants.kt @@ -1,9 +1,8 @@ package app.revanced.patches.music.misc.microg.shared object Constants { - internal const val REVANCED_MUSIC_APP_NAME = "YT Music ReVanced" - internal const val REVANCED_MUSIC_PACKAGE_NAME = "app.revanced.android.apps.youtube.music" + internal const val YOUTUBE_PACKAGE_NAME = "com.google.android.youtube" internal const val MUSIC_PACKAGE_NAME = "com.google.android.apps.youtube.music" internal const val SPOOFED_PACKAGE_NAME = MUSIC_PACKAGE_NAME internal const val SPOOFED_PACKAGE_SIGNATURE = "afb0fed5eeaebdd86f56a97742f4b6b33ef59875" -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/music/misc/optimizeresource/patch/OptimizeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/optimizeresource/patch/OptimizeResourcePatch.kt new file mode 100644 index 000000000..fabe8c46c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/optimizeresource/patch/OptimizeResourcePatch.kt @@ -0,0 +1,33 @@ +package app.revanced.patches.music.misc.optimizeresource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch +@Name("optimize-resource-music") +@Description("Remove unnecessary resources.") +@YouTubeMusicCompatibility +@Version("0.0.1") +class OptimizeResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + val relativePath = "raw/third_party_licenses" + + Files.copy( + this.javaClass.classLoader.getResourceAsStream("youtube/resource/$relativePath")!!, + context["res"].resolve(relativePath).toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/misc/settings/patch/MusicSettingsPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/settings/patch/MusicSettingsPatch.kt new file mode 100644 index 000000000..21ae9576c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/settings/patch/MusicSettingsPatch.kt @@ -0,0 +1,60 @@ +package app.revanced.patches.music.misc.settings.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode +import org.w3c.dom.Element + +@Patch +@Name("music-settings") +@Description("Adds settings for ReVanced to YouTube Music.") +@YouTubeMusicCompatibility +@DependsOn([FixLocaleConfigErrorPatch::class]) +@Version("0.0.1") +class MusicSettingsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + * Copy strings + */ + + context.copyXmlNode("music/settings/host", "values/strings.xml", "resources") + + /* + * Copy colors + */ + + context.xmlEditor["res/values/colors.xml"].use { editor -> + val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + node.textContent = when (node.getAttribute("name")) { + "material_deep_teal_500" -> "@android:color/white" + + else -> continue + } + } + } + + /* + * Copy preference fragments + */ + + context.copyXmlNode("music/settings/host", "xml/settings_headers.xml", "PreferenceScreen") + context.copyXmlNode("music/settings/host", "xml/settings_prefs_compat.xml", "com.google.android.apps.youtube.music.ui.preference.PreferenceCategoryCompat") + + return PatchResultSuccess() + } + +} diff --git a/src/main/kotlin/app/revanced/patches/music/misc/translations/patch/MusicTranslationsPatch.kt b/src/main/kotlin/app/revanced/patches/music/misc/translations/patch/MusicTranslationsPatch.kt new file mode 100644 index 000000000..e1925db99 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/music/misc/translations/patch/MusicTranslationsPatch.kt @@ -0,0 +1,86 @@ +package app.revanced.patches.youtube.misc.translations.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.music.misc.integrations.patch.MusicIntegrationsPatch +import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch +import app.revanced.shared.annotation.YouTubeMusicCompatibility +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch +@DependsOn([MusicIntegrationsPatch::class, MusicSettingsPatch::class]) +@Name("translations-music") +@Description("Add Crowdin Translations for YouTube Music") +@YouTubeMusicCompatibility +@Version("0.0.1") +class MusicTranslationsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + val revanced_translations = "translate" to arrayOf( + "ar-v21", + "az-rAZ-v21", + "bg-rBG-v21", + "bn-rIN-v21", + "bn-v21", + "cs-rCZ-v21", + "de-rDE-v21", + "el-rGR-v21", + "es-rES-v21", + "fi-rFI-v21", + "fr-rFR-v21", + "hi-rIN-v21", + "hu-rHU-v21", + "id-rID-v21", + "in-v21", + "it-rIT-v21", + "ja-rJP-v21", + "kn-rIN-v21", + "ko-rKR-v21", + "ml-rIN-v21", + "nl-rNL-v21", + "pa-rIN-v21", + "pl-rPL-v21", + "pt-rBR-v21", + "pt-rPT-v21", + "ro-rRO-v21", + "ru-rRU-v21", + "sk-rSK-v21", + "sv-rFI-v21", + "sv-rSE-v21", + "ta-rIN-v21", + "th-v21", + "tr-rTR-v21", + "uk-rUA-v21", + "vi-rVN-v21", + "zh-rCN-v21", + "zh-rTW-v21" + ) + + val TranslationsResources = arrayOf(revanced_translations) + + val classLoader = this.javaClass.classLoader + TranslationsResources.forEach { (path, languageNames) -> + languageNames.forEach { name -> + val resDirectory = context["res"].resolve("values-$name") + val relativePath = "values-$name/strings.xml" + + Files.createDirectory(resDirectory.toPath()) + Files.copy( + classLoader.getResourceAsStream("music/$path/$relativePath")!!, + context["res"].resolve(relativePath).toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/annotations/BackgroundPlayCompatibility.kt b/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/annotations/BackgroundPlayCompatibility.kt deleted file mode 100644 index 0c91cb5bd..000000000 --- a/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/annotations/BackgroundPlayCompatibility.kt +++ /dev/null @@ -1,30 +0,0 @@ -package app.revanced.patches.music.premium.backgroundplay.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.apps.youtube.music", - arrayOf( - "5.14.53", - "5.16.51", - "5.17.51", - "5.21.52", - "5.22.54", - "5.23.50", - "5.25.51", - "5.25.52", - "5.26.52", - "5.27.51", - "5.28.52", - "5.29.52", - "5.31.50", - "5.34.51", - "5.36.51" - ) - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class BackgroundPlayCompatibility diff --git a/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/fingerprints/BackgroundPlaybackDisableFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/fingerprints/BackgroundPlaybackDisableFingerprint.kt index fdaea7760..9f625833c 100644 --- a/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/fingerprints/BackgroundPlaybackDisableFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/fingerprints/BackgroundPlaybackDisableFingerprint.kt @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object BackgroundPlaybackDisableFingerprint : MethodFingerprint( "Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( diff --git a/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/patch/BackgroundPlayPatch.kt b/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/patch/BackgroundPlayPatch.kt index 9c860a9c3..b15041b28 100644 --- a/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/patch/BackgroundPlayPatch.kt +++ b/src/main/kotlin/app/revanced/patches/music/premium/backgroundplay/patch/BackgroundPlayPatch.kt @@ -5,17 +5,17 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.music.premium.backgroundplay.annotations.BackgroundPlayCompatibility import app.revanced.patches.music.premium.backgroundplay.fingerprints.BackgroundPlaybackDisableFingerprint +import app.revanced.shared.annotation.YouTubeMusicCompatibility @Patch @Name("background-play") @Description("Enables playing music in the background.") -@BackgroundPlayCompatibility +@YouTubeMusicCompatibility @Version("0.0.1") class BackgroundPlayPatch : BytecodePatch( listOf( diff --git a/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/annotations/UnlockProCompatibility.kt deleted file mode 100644 index e4d8a13e2..000000000 --- a/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/annotations/UnlockProCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.myexpenses.misc.pro.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("org.totschnig.myexpenses")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class UnlockProCompatibility diff --git a/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/fingerprints/IsEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/fingerprints/IsEnabledFingerprint.kt deleted file mode 100644 index caebe9e50..000000000 --- a/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/fingerprints/IsEnabledFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.myexpenses.misc.pro.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object IsEnabledFingerprint : MethodFingerprint( - "Z", - strings = listOf("feature", "feature.licenceStatus") -) diff --git a/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/patch/UnlockProPatch.kt deleted file mode 100644 index ebf34e63e..000000000 --- a/src/main/kotlin/app/revanced/patches/myexpenses/misc/pro/patch/UnlockProPatch.kt +++ /dev/null @@ -1,38 +0,0 @@ -package app.revanced.patches.myexpenses.misc.pro.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.myexpenses.misc.pro.annotations.UnlockProCompatibility -import app.revanced.patches.myexpenses.misc.pro.fingerprints.IsEnabledFingerprint - -@Patch -@Name("unlock-pro") -@Description("Unlocks all professional features.") -@UnlockProCompatibility -@Version("0.0.1") -class UnlockProPatch : BytecodePatch( - listOf( - IsEnabledFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = IsEnabledFingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/annotations/UnlockProCompatibility.kt deleted file mode 100644 index 39c943473..000000000 --- a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/annotations/UnlockProCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.nyx.misc.pro.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.awedea.nyx")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class UnlockProCompatibility diff --git a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt deleted file mode 100644 index 90b0af58d..000000000 --- a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/fingerprints/CheckProFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.nyx.misc.pro.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object CheckProFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("BillingManager;") && methodDef.name == "isProVersion" - } -) diff --git a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/nyx/misc/pro/patch/UnlockProPatch.kt deleted file mode 100644 index bb0ee5960..000000000 --- a/src/main/kotlin/app/revanced/patches/nyx/misc/pro/patch/UnlockProPatch.kt +++ /dev/null @@ -1,38 +0,0 @@ -package app.revanced.patches.nyx.misc.pro.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.nyx.misc.pro.annotations.UnlockProCompatibility -import app.revanced.patches.nyx.misc.pro.fingerprints.CheckProFingerprint - -@Patch -@Name("unlock-pro") -@Description("Unlocks all pro features.") -@UnlockProCompatibility -@Version("0.0.1") -class UnlockProPatch : BytecodePatch( - listOf( - CheckProFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = CheckProFingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt deleted file mode 100644 index 0666c8769..000000000 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/general/annotations/GeneralAdsCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.reddit.ad.general.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.reddit.frontpage")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class GeneralAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/GeneralAdsPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/GeneralAdsPatch.kt deleted file mode 100644 index 86341a62a..000000000 --- a/src/main/kotlin/app/revanced/patches/reddit/ad/general/patch/GeneralAdsPatch.kt +++ /dev/null @@ -1,54 +0,0 @@ -package app.revanced.patches.reddit.ad.general.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.reddit.ad.general.annotations.GeneralAdsCompatibility -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.instruction.BuilderInstruction21c -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.StringReference -import org.jf.dexlib2.immutable.reference.ImmutableStringReference - -@Patch -@Name("general-reddit-ads") -@Description("Removes general ads from the Reddit frontpage and subreddits.") -@GeneralAdsCompatibility -@Version("0.0.1") -class GeneralAdsPatch : BytecodePatch() { - override fun execute(context: BytecodeContext): PatchResult { - context.classes.forEach { classDef -> - classDef.methods.forEach methodLoop@{ method -> - val implementation = method.implementation ?: return@methodLoop - - implementation.instructions.forEachIndexed { i, instruction -> - if (instruction.opcode != Opcode.CONST_STRING) return@forEachIndexed - if (((instruction as ReferenceInstruction).reference as StringReference).string != "AdPost") return@forEachIndexed - - val proxiedClass = context.proxy(classDef).mutableClass - - val proxiedImplementation = proxiedClass.methods.first { - it.name == method.name && it.parameterTypes.containsAll(method.parameterTypes) - }.implementation!! - - var newString = "AdPost1" - if (proxiedImplementation.instructions[i - 1].opcode == Opcode.CONST_STRING) { - newString = "SubredditPost" - } - proxiedImplementation.replaceInstruction( - i, BuilderInstruction21c( - Opcode.CONST_STRING, (proxiedImplementation.instructions[i] as BuilderInstruction21c).registerA, ImmutableStringReference(newString) - ) - ) - } - } - } - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/annotations/PremiumIconCompatibility.kt b/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/annotations/PremiumIconCompatibility.kt deleted file mode 100644 index 11ea3c868..000000000 --- a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/annotations/PremiumIconCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.reddit.layout.premiumicon.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.reddit.frontpage")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PremiumIconCompatibility diff --git a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt b/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt deleted file mode 100644 index bb8bf0d35..000000000 --- a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/fingerprints/PremiumIconFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.reddit.layout.premiumicon.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object PremiumIconFingerprint : MethodFingerprint( - "Z", - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("MyAccount;") && methodDef.name == "isPremiumSubscriber" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/patch/PremiumIconPatch.kt b/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/patch/PremiumIconPatch.kt deleted file mode 100644 index 156c746b9..000000000 --- a/src/main/kotlin/app/revanced/patches/reddit/layout/premiumicon/patch/PremiumIconPatch.kt +++ /dev/null @@ -1,36 +0,0 @@ -package app.revanced.patches.reddit.layout.premiumicon.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.reddit.layout.premiumicon.annotations.PremiumIconCompatibility -import app.revanced.patches.reddit.layout.premiumicon.fingerprints.PremiumIconFingerprint - -@Patch -@Name("premium-icon-reddit") -@Description("Unlocks premium Reddit app icons.") -@PremiumIconCompatibility -@Version("0.0.1") -class PremiumIconPatch : BytecodePatch( - listOf( - PremiumIconFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = PremiumIconFingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarFingerprint.kt deleted file mode 100644 index 572ec2193..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.shared.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SeekbarFingerprint : MethodFingerprint( - "V", - strings = listOf("timed_markers_width") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt b/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt deleted file mode 100644 index 7afcdae85..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/fingerprints/SeekbarOnDrawFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.shared.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SeekbarOnDrawFingerprint : MethodFingerprint( - customFingerprint = { it.name == "onDraw" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt deleted file mode 100644 index 1853a97c6..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BasePreference.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * 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 { - - /** - * Serialize preference element to XML. - * Overriding methods should invoke super and operate on its return value. - * @param ownerDocument Target document to create elements from. - * @param resourceCallback Called when a resource has been processed. - */ - open fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)? = null): Element { - return ownerDocument.createElement(tag).apply { - if(key.isNotEmpty()) - setAttribute("android:key", key) - setAttribute("android:title", "@string/${title.also { resourceCallback?.invoke(it) }.name}") - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt deleted file mode 100644 index 5c5e4174b..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/BaseResource.kt +++ /dev/null @@ -1,26 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * Base resource class for all resources. - * - * @param name The name of the resource. - */ -internal abstract class BaseResource( - override val name: String -) : IResource { - - /** - * Serialize resource element to XML. - * Overriding methods should invoke super and operate on its return value. - * @param ownerDocument Target document to create elements from. - * @param resourceCallback Called when a resource has been processed. - */ - open fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)? = null): Element { - return ownerDocument.createElement(tag).apply { - setAttribute("name", name) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt deleted file mode 100644 index b0e8ddbd6..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/ComponentsExtensions.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource -import org.w3c.dom.Element -import org.w3c.dom.Node - -/** - * Add a resource node child - * - * @param resource The resource to add. - * @param resourceCallback Called when a resource has been processed. - */ -internal fun Node.addResource(resource: BaseResource, resourceCallback: ((IResource) -> Unit)? = null) { - appendChild(resource.serialize(ownerDocument, resourceCallback)) -} - -/** - * Add a preference node child to the settings. - * - * @param preference The preference to add. - * @param resourceCallback Called when a resource has been processed. - */ -internal fun Node.addPreference(preference: BasePreference, resourceCallback: ((IResource) -> Unit)? = null) { - appendChild(preference.serialize(ownerDocument, resourceCallback)) -} - -internal fun Element.addSummary(summaryResource: StringResource?, summaryType: SummaryType = SummaryType.DEFAULT) = - summaryResource?.let { summary -> - setAttribute("android:${summaryType.type}", "@string/${summary.name}") - } - -internal fun 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}") - } - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/IPreference.kt deleted file mode 100644 index ec31835ba..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IPreference.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -import app.revanced.patches.shared.settings.preference.impl.StringResource - -/** - * Preference - */ -internal interface IPreference { - /** - * Key of the preference. - */ - val key: String - - /** - * Title of the preference. - */ - val title: StringResource - - /** - * Tag name of the preference. - */ - val tag: String -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/IResource.kt deleted file mode 100644 index dc3fe610e..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/IResource.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -/** - * Resource - */ -internal interface IResource { - /** - * Name of the resource. - */ - val name: String - - /** - * Tag name of the resource. - */ - val tag: String -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/SummaryType.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/SummaryType.kt deleted file mode 100644 index 006f6986c..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/SummaryType.kt +++ /dev/null @@ -1,5 +0,0 @@ -package app.revanced.patches.shared.settings.preference - -enum class SummaryType(val type: String) { - DEFAULT("summary"), ON("summaryOn"), OFF("summaryOff") -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt deleted file mode 100644 index 608dccca4..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ArrayResource.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.IResource -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * Represents an array resource. - * - * @param name The name of the array resource. - * @param items The items of the array resource. - */ -internal data class ArrayResource( - override val name: String, - val items: List -) : BaseResource(name) { - override val tag = "string-array" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("name", name) - - items.forEach { item -> - resourceCallback?.invoke(item) - - this.appendChild(ownerDocument.createElement("item").also { itemNode -> - itemNode.textContent = "@string/${item.name}" - }) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt deleted file mode 100644 index 09432143b..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/InputType.kt +++ /dev/null @@ -1,6 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -enum class InputType(val type: String) { - STRING("text"), - NUMBER("number"), -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt deleted file mode 100644 index 9f2f9f84e..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/ListPreference.kt +++ /dev/null @@ -1,38 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addDefault -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * List preference. - * - * @param key The key of the list preference. - * @param title The title of the list preference. - * @param entries The human-readable entries of the list preference. - * @param entryValues The entry values of the list preference. - * @param default The default entry value of the list preference. - * @param summary The summary of the list preference. - */ -internal class ListPreference( - key: String, - title: StringResource, - val entries: ArrayResource, - val entryValues: ArrayResource, - val default: String? = null, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "ListPreference" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("android:entries", "@array/${entries.also { resourceCallback?.invoke(it) }.name}") - setAttribute("android:entryValues", "@array/${entryValues.also { resourceCallback?.invoke(it) }.name}") - addDefault(default) - addSummary(summary) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt deleted file mode 100644 index fcacd61d7..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/Preference.kt +++ /dev/null @@ -1,44 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * 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( - key: String, - title: StringResource, - val intent: Intent, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "Preference" - - /* Key-less constructor */ - constructor( - title: StringResource, - intent: Intent, - summary: StringResource? = null - ) : this("", title, intent, summary) - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary?.also { resourceCallback?.invoke(it) }) - - this.appendChild(ownerDocument.createElement("intent").also { intentNode -> - intentNode.setAttribute("android:targetPackage", intent.targetPackage) - intentNode.setAttribute("android:data", intent.data) - intentNode.setAttribute("android:targetClass", intent.targetClass) - }) - } - } - - data class Intent(val targetPackage: String, val data: String, val targetClass: String) -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt deleted file mode 100644 index f575dfe3a..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceCategory.kt +++ /dev/null @@ -1,29 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * Preference category. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param preferences Child preferences of this category. - */ -internal open class PreferenceCategory( - key: String, - title: StringResource, - var preferences: List -) : BasePreference(key, title) { - override val tag: String = "PreferenceCategory" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - for (childPreference in preferences) { - this.appendChild(childPreference.serialize(ownerDocument, resourceCallback)) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt deleted file mode 100644 index b7c82ba6f..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/PreferenceScreen.kt +++ /dev/null @@ -1,34 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * 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, - var preferences: List, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "PreferenceScreen" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - addSummary(summary?.also { resourceCallback?.invoke(it) }) - - for (childPreference in preferences) { - this.appendChild(childPreference.serialize(ownerDocument, resourceCallback)) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt deleted file mode 100644 index 49471faa8..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/StringResource.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BaseResource -import app.revanced.patches.shared.settings.preference.IResource -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * Represents a string value in the strings.xml file - * - * @param name The name of the string - * @param value The value of the string - * @param formatted If the string is formatted. If false, the attribute will be set - */ -internal data class StringResource( - override val name: String, - val value: String, - val formatted: Boolean = true -) : BaseResource(name) { - override val tag = "string" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - // if the string is un-formatted, explicitly add the formatted attribute - if (!formatted) - setAttribute("formatted", "false") - - textContent = value - } - } -} diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt deleted file mode 100644 index 78d9f1d38..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/SwitchPreference.kt +++ /dev/null @@ -1,35 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addDefault -import app.revanced.patches.shared.settings.preference.addSummary -import app.revanced.patches.shared.settings.preference.SummaryType -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * 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, - val summaryOn: StringResource? = null, - val summaryOff: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "SwitchPreference" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - addDefault(default) - addSummary(summaryOn?.also { resourceCallback?.invoke(it) }, SummaryType.ON) - addSummary(summaryOff?.also { resourceCallback?.invoke(it) }, SummaryType.OFF) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt b/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt deleted file mode 100644 index 907a4a160..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/preference/impl/TextPreference.kt +++ /dev/null @@ -1,35 +0,0 @@ -package app.revanced.patches.shared.settings.preference.impl - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addDefault -import app.revanced.patches.shared.settings.preference.addSummary -import org.w3c.dom.Document -import org.w3c.dom.Element - -/** - * 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, - val default: String? = null, - val summary: StringResource? = null -) : BasePreference(key, title) { - override val tag: String = "EditTextPreference" - - override fun serialize(ownerDocument: Document, resourceCallback: ((IResource) -> Unit)?): Element { - return super.serialize(ownerDocument, resourceCallback).apply { - setAttribute("android:inputType", inputType.type) - addDefault(default) - addSummary(summary?.also { resourceCallback?.invoke(it) }) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt deleted file mode 100644 index f62c24b21..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/resource/patch/AbstractSettingsResourcePatch.kt +++ /dev/null @@ -1,135 +0,0 @@ -package app.revanced.patches.shared.settings.resource.patch - -import app.revanced.patcher.data.DomFileEditor -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.IResource -import app.revanced.patches.shared.settings.preference.addPreference -import app.revanced.patches.shared.settings.preference.addResource -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources -import org.w3c.dom.Node - -/** - * Abstract settings resource patch - * - * @param preferenceFileName Name of the settings preference xml file - * @param sourceDirectory Source directory to copy the preference template from - */ -abstract class AbstractSettingsResourcePatch( - private val preferenceFileName: String, - private val sourceDirectory: String, -) : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - /* - * used for self-restart - */ - context.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") - }) - } - } - - /* copy preference template from source dir */ - context.copyResources( - sourceDirectory, - ResourceUtils.ResourceGroup( - "xml", "$preferenceFileName.xml" - ) - ) - - /* prepare xml editors */ - stringsEditor = context.xmlEditor["res/values/strings.xml"] - arraysEditor = context.xmlEditor["res/values/arrays.xml"] - revancedPreferencesEditor = context.xmlEditor["res/xml/$preferenceFileName.xml"] - - return PatchResultSuccess() - } - - internal companion object { - private var revancedPreferenceNode: Node? = null - private var stringsNode: Node? = null - private var arraysNode: Node? = null - - private var strings = mutableListOf() - - private var revancedPreferencesEditor: DomFileEditor? = null - set(value) { - field = value - revancedPreferenceNode = 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!!.addResource(arrayResource) { it.include() } - - /** - * Add a preference to the settings. - * - * @param preference The preference to add. - */ - fun addPreference(preference: BasePreference) = - revancedPreferenceNode!!.addPreference(preference) { it.include() } - - /** - * Add a new resource to the resources. - * - * @throws IllegalArgumentException if the resource already exists. - */ - internal fun IResource.include() { - when (this) { - is StringResource -> { - if (strings.any { it.name == name }) return - strings.add(this) - } - - is ArrayResource -> addArray(this) - else -> throw NotImplementedError("Unsupported resource type") - } - } - - internal fun DomFileEditor?.getNode(tagName: String) = this!!.file.getElementsByTagName(tagName).item(0) - } - - override fun close() { - // merge all strings, skip duplicates - strings.forEach { - stringsNode!!.addResource(it) - } - - revancedPreferencesEditor?.close() - stringsEditor?.close() - arraysEditor?.close() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt b/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt deleted file mode 100644 index a257af9a2..000000000 --- a/src/main/kotlin/app/revanced/patches/shared/settings/util/AbstractPreferenceScreen.kt +++ /dev/null @@ -1,89 +0,0 @@ -package app.revanced.patches.shared.settings.util - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.impl.PreferenceCategory -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import java.io.Closeable - -internal abstract class AbstractPreferenceScreen( - private val root: MutableList = mutableListOf() -) : Closeable { - - override fun close() { - if (root.isEmpty()) - return - - for (preference in root.sortedBy { it.title }) { - commit(preference.transform()) - } - } - - /** - * Finalize and insert root preference into resource patch - */ - abstract fun commit(screen: PreferenceScreen) - - open inner class Screen( - key: String, - title: String, - val summary: String? = null, - preferences: MutableList = mutableListOf(), - val categories: MutableList = mutableListOf() - ) : BasePreferenceCollection(key, title, preferences) { - override fun transform(): PreferenceScreen { - return PreferenceScreen( - key, - StringResource("${key}_title", title), - preferences.sortedBy { it.title.value } + - categories.sortedBy { it.title }.map { it.transform() }, - summary?.let { summary -> - StringResource("${key}_summary", summary) - } - ) - } - - private fun ensureScreenInserted() { - // Add to screens if not yet done - if(!this@AbstractPreferenceScreen.root.contains(this)) - this@AbstractPreferenceScreen.root.add(this) - } - - fun addPreferences(vararg preferences: BasePreference) { - ensureScreenInserted() - this.preferences.addAll(preferences) - } - - open inner class Category( - key: String, - title: String, - preferences: MutableList = mutableListOf() - ): BasePreferenceCollection(key, title, preferences) { - override fun transform(): PreferenceCategory { - return PreferenceCategory( - key, - StringResource("${key}_title", title), - preferences.sortedBy { it.title.value } - ) - } - - fun addPreferences(vararg preferences: BasePreference) { - ensureScreenInserted() - - // Add to categories if not yet done - if(!this@Screen.categories.contains(this)) - this@Screen.categories.add(this) - - this.preferences.addAll(preferences) - } - } - } - - abstract class BasePreferenceCollection( - val key: String, - val title: String, - val preferences: MutableList = mutableListOf() - ) { - abstract fun transform(): BasePreference - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/annotation/DisableCaptureRestrictionCompatibility.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/annotation/DisableCaptureRestrictionCompatibility.kt deleted file mode 100644 index 3aad515bd..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/annotation/DisableCaptureRestrictionCompatibility.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.spotify.audio.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package("com.spotify.music")] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DisableCaptureRestrictionCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt deleted file mode 100644 index 88aae6a28..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/bytecode/patch/DisableCaptureRestrictionBytecodePatch.kt +++ /dev/null @@ -1,86 +0,0 @@ -package app.revanced.patches.spotify.audio.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCompatibility -import app.revanced.patches.spotify.audio.fingerprints.DisableCaptureRestrictionAudioDriverFingerprint -import app.revanced.patches.spotify.audio.resource.patch.DisableCaptureRestrictionResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.MethodReference - -@Patch -@Name("disable-capture-restriction") -@DependsOn([DisableCaptureRestrictionResourcePatch::class]) -@Description("Allows capturing Spotify's audio output while screen sharing or screen recording.") -@DisableCaptureRestrictionCompatibility -@Version("0.0.2") -class DisableCaptureRestrictionBytecodePatch : BytecodePatch( - listOf( - DisableCaptureRestrictionAudioDriverFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = DisableCaptureRestrictionAudioDriverFingerprint.result!!.mutableMethod - - var invokePosition: Int? = null - var invokeParamRegister: Int? = null - - // Find INVOKE_VIRTUAL opcode with call to AudioAttributesBuilder.setAllowedCapturePolicy(I) - for ((index, instruction) in method.implementation!!.instructions.withIndex()) { - if(instruction.opcode != Opcode.INVOKE_VIRTUAL) - continue - - val methodName = ((instruction as ReferenceInstruction).reference as MethodReference).name - if (methodName != "setAllowedCapturePolicy") - continue - - // Store register of the integer parameter for setAllowedCapturePolicy - invokeParamRegister = (instruction as FiveRegisterInstruction).registerD - invokePosition = index - } - - if(invokePosition == null || invokeParamRegister == null) - return PatchResultError("Cannot find setAllowedCapturePolicy method call") - - // Walk back to the const/4 instruction that sets the parameter register - var matchFound = false - for (index in invokePosition downTo 0) { - val instruction = method.instruction(index) - if(instruction.opcode != Opcode.CONST_4) - continue - - val register = (instruction as OneRegisterInstruction).registerA - if(register != invokeParamRegister) - continue - - // Replace parameter value - method.replaceInstruction( - index, "const/4 v$register, $ALLOW_CAPTURE_BY_ALL" - ) - matchFound = true - break - } - - return if (matchFound) - PatchResultSuccess() - else - PatchResultError("Const instruction not found") - } - - private companion object { - const val ALLOW_CAPTURE_BY_ALL = 0x01 - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt deleted file mode 100644 index 191755518..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/fingerprints/DisableCaptureRestrictionAudioDriverFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.spotify.audio.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object DisableCaptureRestrictionAudioDriverFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass == "Lcom/spotify/playback/playbacknative/AudioDriver;" && methodDef.name == "constructAudioAttributes" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt deleted file mode 100644 index 5088cce81..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/audio/resource/patch/DisableCaptureRestrictionResourcePatch.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.patches.spotify.audio.resource.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patches.spotify.audio.annotation.DisableCaptureRestrictionCompatibility -import org.w3c.dom.Element - -@Name("disable-capture-restriction-resource-patch") -@Description("Sets allowAudioPlaybackCapture in manifest to true.") -@DisableCaptureRestrictionCompatibility -@Version("0.0.2") -class DisableCaptureRestrictionResourcePatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - // create an xml editor instance - context.xmlEditor["AndroidManifest.xml"].use { dom -> - // get the application node - val applicationNode = dom - .file - .getElementsByTagName("application") - .item(0) as Element - - // set allowAudioPlaybackCapture attribute to true - applicationNode.setAttribute("android:allowAudioPlaybackCapture", "true") - } - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/layout/theme/annotations/ThemeCompatibility.kt b/src/main/kotlin/app/revanced/patches/spotify/layout/theme/annotations/ThemeCompatibility.kt deleted file mode 100644 index bc24c3996..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/layout/theme/annotations/ThemeCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.spotify.layout.theme.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.spotify.music")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ThemeCompatibility diff --git a/src/main/kotlin/app/revanced/patches/spotify/layout/theme/patch/ThemePatch.kt b/src/main/kotlin/app/revanced/patches/spotify/layout/theme/patch/ThemePatch.kt deleted file mode 100644 index dfbc7fd17..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/layout/theme/patch/ThemePatch.kt +++ /dev/null @@ -1,66 +0,0 @@ -package app.revanced.patches.spotify.layout.theme.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.* -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.spotify.layout.theme.annotations.ThemeCompatibility -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import org.w3c.dom.Element - -@Patch -@DependsOn([FixLocaleConfigErrorPatch::class]) -@Name("spotify-theme") -@Description("Applies a custom theme.") -@ThemeCompatibility -@Version("0.0.1") -class ThemePatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - context.xmlEditor["res/values/colors.xml"].use { editor -> - val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element - - for (i in 0 until resourcesNode.childNodes.length) { - val node = resourcesNode.childNodes.item(i) as? Element ?: continue - - node.textContent = when (node.getAttribute("name")) { - "gray_7" -> backgroundColor!! - "dark_brightaccent_background_base", "dark_base_text_brightaccent", "green_light" -> accentColor!! - "dark_brightaccent_background_press" -> accentPressedColor!! - else -> continue - } - } - } - - return PatchResultSuccess() - } - - companion object : OptionsContainer() { - var backgroundColor: String? by option( - PatchOption.StringOption( - key = "backgroundColor", - default = "@android:color/black", - title = "Background color", - description = "The background color. Can be a hex color or a resource reference.", - ) - ) - var accentColor: String? by option( - PatchOption.StringOption( - key = "accentColor", - default = "#ff1ed760", - title = "Accent color", - description = "The accent color ('spotify green' by default). Can be a hex color or a resource reference.", - ) - ) - var accentPressedColor: String? by option( - PatchOption.StringOption( - key = "accentPressedColor", - default = "#ff169c46", - title = "Pressed accent for the dark theme", - description = "The color when accented buttons are pressed, by default slightly darker than accent. Can be a hex color or a resource reference.", - ) - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/annotations/PremiumNavbarTabCompatibility.kt b/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/annotations/PremiumNavbarTabCompatibility.kt deleted file mode 100644 index 41f65315b..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/annotations/PremiumNavbarTabCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.spotify.premium_navbar_tab.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.spotify.music")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PremiumNavbarTabCompatibility diff --git a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/fingerprints/AddPremiumNavbarTabFingerprint.kt b/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/fingerprints/AddPremiumNavbarTabFingerprint.kt deleted file mode 100644 index 296c87f8d..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/fingerprints/AddPremiumNavbarTabFingerprint.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.patches.spotify.premium_navbar_tab.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object AddPremiumNavbarTabFingerprint : MethodFingerprint( - parameters = listOf("L", "L", "L", "L", "L", "L") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/fingerprints/AddPremiumNavbarTabParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/fingerprints/AddPremiumNavbarTabParentFingerprint.kt deleted file mode 100644 index e67bd8f6b..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/fingerprints/AddPremiumNavbarTabParentFingerprint.kt +++ /dev/null @@ -1,7 +0,0 @@ -package app.revanced.patches.spotify.premium_navbar_tab.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object AddPremiumNavbarTabParentFingerprint : MethodFingerprint( - strings = listOf("com.samsung.android.samsungaccount.action.REQUEST_AUTHCODE") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/patch/PremiumNavbarTabPatch.kt b/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/patch/PremiumNavbarTabPatch.kt deleted file mode 100644 index e45bb6fbe..000000000 --- a/src/main/kotlin/app/revanced/patches/spotify/premium_navbar_tab/patch/PremiumNavbarTabPatch.kt +++ /dev/null @@ -1,63 +0,0 @@ -package app.revanced.patches.spotify.premium_navbar_tab.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.spotify.premium_navbar_tab.annotations.PremiumNavbarTabCompatibility -import app.revanced.patches.spotify.premium_navbar_tab.fingerprints.AddPremiumNavbarTabFingerprint -import app.revanced.patches.spotify.premium_navbar_tab.fingerprints.AddPremiumNavbarTabParentFingerprint -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -@Patch -@Name("hide-premium-navbar") -@Description("Removes the premium tab from the navbar.") -@PremiumNavbarTabCompatibility -@Version("0.0.1") -@DependsOn([ResourceMappingPatch::class]) -class PremiumNavbarTabPatch : BytecodePatch( - listOf( - AddPremiumNavbarTabParentFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val parentResult = AddPremiumNavbarTabParentFingerprint.result!! - AddPremiumNavbarTabFingerprint.resolve(context, parentResult.classDef) - - val result = AddPremiumNavbarTabFingerprint.result!! - - val method = result.mutableMethod - val methodInstructions = method.implementation!!.instructions - val lastInstructionIdx = methodInstructions.size - 1 - - val premiumTabId = - ResourceMappingPatch.resourceMappings.single { it.type == "id" && it.name == "premium_tab" }.id - - var removeAmount = 2 - // 2nd const remove method - for ((i, instruction) in methodInstructions.asReversed().withIndex()) { - if (instruction.opcode.ordinal != Opcode.CONST.ordinal) continue - if ((instruction as WideLiteralInstruction).wideLiteral != premiumTabId) continue - - val findThreshold = 10 - val constIndex = lastInstructionIdx - i - val invokeInstruction = methodInstructions.subList(constIndex, constIndex + findThreshold).first { - it.opcode.ordinal == Opcode.INVOKE_VIRTUAL_RANGE.ordinal - } - method.removeInstruction(methodInstructions.indexOf(invokeInstruction)) - - if (--removeAmount == 0) break - } - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/annotations/UnlockThemesCompatibility.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/annotations/UnlockThemesCompatibility.kt deleted file mode 100644 index cc096640e..000000000 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/annotations/UnlockThemesCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.ticktick.misc.themeunlock.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.ticktick.task")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class UnlockThemesCompatibility diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt deleted file mode 100644 index dccab403f..000000000 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/CheckLockedThemesFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.ticktick.misc.themeunlock.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object CheckLockedThemesFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("Theme;") && methodDef.name == "isLockedTheme" - } -) diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt deleted file mode 100644 index dc22b02c5..000000000 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/fingerprints/SetThemeFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.ticktick.misc.themeunlock.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SetThemeFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("ThemePreviewActivity;") && methodDef.name == "lambda\$updateUserBtn\$1" - } -) diff --git a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt b/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt deleted file mode 100644 index e1b6664e7..000000000 --- a/src/main/kotlin/app/revanced/patches/ticktick/misc/themeunlock/patch/UnlockThemePatch.kt +++ /dev/null @@ -1,43 +0,0 @@ -package app.revanced.patches.ticktick.misc.themeunlock.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.ticktick.misc.themeunlock.annotations.UnlockThemesCompatibility -import app.revanced.patches.ticktick.misc.themeunlock.fingerprints.CheckLockedThemesFingerprint -import app.revanced.patches.ticktick.misc.themeunlock.fingerprints.SetThemeFingerprint - -@Patch -@Name("unlock-themes") -@Description("Unlocks all themes.") -@UnlockThemesCompatibility -@Version("0.0.1") -class UnlockProPatch : BytecodePatch( - listOf( - CheckLockedThemesFingerprint, - SetThemeFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val lockedThemesMethod = CheckLockedThemesFingerprint.result!!.mutableMethod - lockedThemesMethod.addInstructions( - 0, - """ - const/4 v0, 0x0 - return v0 - """ - ) - - val setThemeMethod = SetThemeFingerprint.result!!.mutableMethod - setThemeMethod.removeInstructions(0, 9) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/tiktok/ad/annotations/HideAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/ad/annotations/HideAdsCompatibility.kt deleted file mode 100644 index 529acafbf..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/ad/annotations/HideAdsCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.ad.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideAdsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt deleted file mode 100644 index fc252a24c..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/ConvertHelpFeedItemListFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.tiktok.ad.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object ConvertHelpFeedItemListFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/ConvertHelp;") && - methodDef.name.endsWith("${'$'}FeedItemList") - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt deleted file mode 100644 index 4f9de5d3a..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/ad/fingerprints/FeedItemListCloneFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.tiktok.ad.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object FeedItemListCloneFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/FeedItemList;") && methodDef.name == "clone" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/ad/patch/HideAdsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/ad/patch/HideAdsPatch.kt deleted file mode 100644 index 862f80517..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/ad/patch/HideAdsPatch.kt +++ /dev/null @@ -1,57 +0,0 @@ -package app.revanced.patches.tiktok.ad.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.tiktok.ad.annotations.HideAdsCompatibility -import app.revanced.patches.tiktok.ad.fingerprints.ConvertHelpFeedItemListFingerprint -import app.revanced.patches.tiktok.ad.fingerprints.FeedItemListCloneFingerprint -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction -import org.jf.dexlib2.iface.reference.FieldReference - -@Patch -@Name("hide-ads") -@Description("Removes ads from TikTok.") -@HideAdsCompatibility -@Version("0.0.1") -class HideAdsPatch : BytecodePatch( - listOf( - FeedItemListCloneFingerprint, - ConvertHelpFeedItemListFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - listOf( - FeedItemListCloneFingerprint, - ConvertHelpFeedItemListFingerprint - ).forEach { fingerprint -> - val method = fingerprint.result!!.mutableMethod - // iterate all instructions in the clone method - for ((index, instruction) in method.implementation!!.instructions.withIndex()) { - // conditions for the instruction we need - if (instruction.opcode.ordinal != Opcode.IPUT_OBJECT.ordinal) continue - val preloadAdsFieldInstruction = (instruction as? ReferenceInstruction) - if ((preloadAdsFieldInstruction?.reference as? FieldReference)?.name != "preloadAds") continue - - // set null instead of the field "preloadAds" - val overrideRegister = (preloadAdsFieldInstruction as TwoRegisterInstruction).registerA - method.addInstruction( - index, - "const/4 v$overrideRegister, 0x0" - ) - return@forEach - } - return PatchResultError("Can not find required instruction.") - } - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/annotations/FeedFilterCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/annotations/FeedFilterCompatibility.kt deleted file mode 100644 index d33f69851..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/annotations/FeedFilterCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.feedfilter.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class FeedFilterCompatibility diff --git a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt deleted file mode 100644 index e2f05c0ef..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/fingerprints/FeedApiServiceLIZFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.tiktok.feedfilter.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object FeedApiServiceLIZFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.STATIC or AccessFlags.FINAL or AccessFlags.SYNTHETIC, - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/FeedApiService;") && methodDef.name == "LIZ" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/patch/FeedFilterPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/patch/FeedFilterPatch.kt deleted file mode 100644 index fb6ba0b32..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/patch/FeedFilterPatch.kt +++ /dev/null @@ -1,51 +0,0 @@ -package app.revanced.patches.tiktok.feedfilter.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.tiktok.feedfilter.annotations.FeedFilterCompatibility -import app.revanced.patches.tiktok.feedfilter.fingerprints.FeedApiServiceLIZFingerprint -import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint -import app.revanced.patches.tiktok.misc.settings.patch.SettingsPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("feed-filter") -@Description("Filters tiktok videos: removing ads, removing livestreams.") -@FeedFilterCompatibility -@Version("0.0.1") -class FeedFilterPatch : BytecodePatch( - listOf( - FeedApiServiceLIZFingerprint, - SettingsStatusLoadFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = FeedApiServiceLIZFingerprint.result!!.mutableMethod - for ((index, instruction) in method.implementation!!.instructions.withIndex()) { - if (instruction.opcode != Opcode.RETURN_OBJECT) continue - val feedItemsRegister = (instruction as OneRegisterInstruction).registerA - method.addInstruction( - index, - "invoke-static {v$feedItemsRegister}, Lapp/revanced/tiktok/feedfilter/FeedItemsFilter;->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V" - ) - break - } - val method2 = SettingsStatusLoadFingerprint.result!!.mutableMethod - method2.addInstruction( - 0, - "invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsStatus;->enableFeedFilter()V" - ) - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/annotations/DownloadsCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/annotations/DownloadsCompatibility.kt deleted file mode 100644 index 2a353e839..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/annotations/DownloadsCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.interaction.downloads.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DownloadsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt deleted file mode 100644 index f1e851661..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.interaction.downloads.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object ACLCommonShareFingerprint : MethodFingerprint( - "I", - AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/ACLCommonShare;") && - methodDef.name == "getCode" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt deleted file mode 100644 index 384530db7..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint2.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.tiktok.interaction.downloads.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.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility -import org.jf.dexlib2.AccessFlags - -@Name("acl-common-share-get-show-type") -@DownloadsCompatibility -@Version("0.0.1") -object ACLCommonShareFingerprint2 : MethodFingerprint( - "I", - AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/ACLCommonShare;") && - methodDef.name == "getShowType" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt deleted file mode 100644 index cf585dd21..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/ACLCommonShareFingerprint3.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.tiktok.interaction.downloads.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.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility -import org.jf.dexlib2.AccessFlags - -@Name("acl-common-share-get-transcode") -@DownloadsCompatibility -@Version("0.0.1") -object ACLCommonShareFingerprint3 : MethodFingerprint( - "I", - AccessFlags.PUBLIC or AccessFlags.FINAL, - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/ACLCommonShare;") && - methodDef.name == "getTranscode" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt deleted file mode 100644 index 8daff09e4..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.tiktok.interaction.downloads.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object DownloadPathParentFingerprint : MethodFingerprint( - "V", - AccessFlags.PUBLIC or AccessFlags.FINAL, - strings = listOf( - "code", - "reason", - "params insufficient" - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt deleted file mode 100644 index a3ea7572f..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt +++ /dev/null @@ -1,131 +0,0 @@ -package app.revanced.patches.tiktok.interaction.downloads.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.extensions.replaceInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility -import app.revanced.patches.tiktok.interaction.downloads.fingerprints.ACLCommonShareFingerprint -import app.revanced.patches.tiktok.interaction.downloads.fingerprints.ACLCommonShareFingerprint2 -import app.revanced.patches.tiktok.interaction.downloads.fingerprints.ACLCommonShareFingerprint3 -import app.revanced.patches.tiktok.interaction.downloads.fingerprints.DownloadPathParentFingerprint -import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint -import app.revanced.patches.tiktok.misc.settings.patch.SettingsPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.StringReference - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("downloads") -@Description("Removes download restrictions and changes the default path to download to.") -@DownloadsCompatibility -@Version("0.0.1") -class DownloadsPatch : BytecodePatch( - listOf( - ACLCommonShareFingerprint, - ACLCommonShareFingerprint2, - ACLCommonShareFingerprint3, - DownloadPathParentFingerprint, - SettingsStatusLoadFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method1 = ACLCommonShareFingerprint.result!!.mutableMethod - method1.replaceInstructions( - 0, - """ - const/4 v0, 0x0 - return v0 - """ - ) - val method2 = ACLCommonShareFingerprint2.result!!.mutableMethod - method2.replaceInstructions( - 0, - """ - const/4 v0, 0x2 - return v0 - """ - ) - //Download videos without watermark. - val method3 = ACLCommonShareFingerprint3.result!!.mutableMethod - method3.addInstructions( - 0, - """ - invoke-static {}, Lapp/revanced/tiktok/download/DownloadsPatch;->shouldRemoveWatermark()Z - move-result v0 - if-eqz v0, :noremovewatermark - const/4 v0, 0x1 - return v0 - :noremovewatermark - nop - """ - ) - //Change the download path patch - val method4 = DownloadPathParentFingerprint.result!!.mutableMethod - val implementation4 = method4.implementation - val instructions = implementation4!!.instructions - var targetOffset = -1 - //Search for the target method called instruction offset. - for ((index, instruction) in instructions.withIndex()) { - if (instruction.opcode != Opcode.CONST_STRING) continue - val reference = (instruction as ReferenceInstruction).reference as StringReference - if (reference.string != "video/mp4") continue - val targetInstruction = instructions[index + 1] - if (targetInstruction.opcode != Opcode.INVOKE_STATIC) continue - targetOffset = index + 1 - break - } - if (targetOffset == -1) return PatchResultError("Can not find download path uri method.") - //Change videos' download path. - val downloadUriMethod = context - .toMethodWalker(DownloadPathParentFingerprint.result!!.method) - .nextMethod(targetOffset, true) - .getMethod() as MutableMethod - downloadUriMethod.implementation!!.instructions.forEachIndexed { index, instruction -> - if (instruction.opcode == Opcode.SGET_OBJECT) { - val overrideRegister = (instruction as OneRegisterInstruction).registerA - downloadUriMethod.addInstructions( - index + 1, - """ - invoke-static {}, Lapp/revanced/tiktok/download/DownloadsPatch;->getDownloadPath()Ljava/lang/String; - move-result-object v$overrideRegister - """ - ) - } - if (instruction.opcode == Opcode.CONST_STRING) { - val string = ((instruction as ReferenceInstruction).reference as StringReference).string - if (string.contains("/Camera")) { - val overrideRegister = (instruction as OneRegisterInstruction).registerA - val overrideString = string.replace("/Camera", "") - downloadUriMethod.replaceInstruction( - index, - """ - const-string v$overrideRegister, "$overrideString" - """ - ) - } - } - } - val method5 = SettingsStatusLoadFingerprint.result!!.mutableMethod - method5.addInstruction( - 0, - "invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsStatus;->enableDownload()V" - ) - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/annotations/ShowSeekbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/annotations/ShowSeekbarCompatibility.kt deleted file mode 100644 index 713de9423..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/annotations/ShowSeekbarCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.interaction.seekbar.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ShowSeekbarCompatibility diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt deleted file mode 100644 index fb6463186..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/fingerprints/AwemeGetVideoControlFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.tiktok.interaction.seekbar.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object AwemeGetVideoControlFingerprint : MethodFingerprint( - "L", - AccessFlags.PUBLIC.value, - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/Aweme;") && methodDef.name == "getVideoControl" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/patch/ShowSeekbarPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/patch/ShowSeekbarPatch.kt deleted file mode 100644 index 0c99ab370..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/seekbar/patch/ShowSeekbarPatch.kt +++ /dev/null @@ -1,47 +0,0 @@ -package app.revanced.patches.tiktok.interaction.seekbar.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.tiktok.interaction.seekbar.annotations.ShowSeekbarCompatibility -import app.revanced.patches.tiktok.interaction.seekbar.fingerprints.AwemeGetVideoControlFingerprint -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.instruction.BuilderInstruction11n -import org.jf.dexlib2.builder.instruction.BuilderInstruction22c - -@Patch -@Name("show-seekbar") -@Description("Shows progress bar for all video.") -@ShowSeekbarCompatibility -@Version("0.0.1") -class ShowSeekbarPatch : BytecodePatch( - listOf( - AwemeGetVideoControlFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - //Get VideoControl FieldReference - val videoControl = context.findClass { it.type.endsWith("/VideoControl;") } - ?: return PatchResultError("Can not find target class") - val fieldList = videoControl.immutableClass.fields.associateBy { field -> field.name } - - val method = AwemeGetVideoControlFingerprint.result!!.mutableMethod - val implementation = method.implementation!! - implementation.addInstructions( - 1, listOf( - BuilderInstruction11n(Opcode.CONST_4, 1, 1), - BuilderInstruction22c(Opcode.IPUT, 1, 0, fieldList["showProgressBar"]!!), - BuilderInstruction22c(Opcode.IPUT, 1, 0, fieldList["draftProgressBar"]!!) - ) - ) - return PatchResultSuccess() - } - -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/annotations/PlaybackSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/annotations/PlaybackSpeedCompatibility.kt deleted file mode 100644 index 33c3dc45b..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/annotations/PlaybackSpeedCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.interaction.speed.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PlaybackSpeedCompatibility diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt deleted file mode 100644 index 4e70ca812..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/fingerprints/SpeedControlParentFingerprint.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.tiktok.interaction.speed.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object SpeedControlParentFingerprint : MethodFingerprint( - returnType = "L", - access = AccessFlags.PRIVATE or AccessFlags.FINAL, - parameters = listOf( - "L" - ), - strings = listOf( - "playback_speed" - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/patch/PlaybackSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/patch/PlaybackSpeedPatch.kt deleted file mode 100644 index c1f15a75d..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/patch/PlaybackSpeedPatch.kt +++ /dev/null @@ -1,48 +0,0 @@ -package app.revanced.patches.tiktok.interaction.speed.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.tiktok.interaction.speed.annotations.PlaybackSpeedCompatibility -import app.revanced.patches.tiktok.interaction.speed.fingerprints.SpeedControlParentFingerprint -import org.jf.dexlib2.Opcode - -@Patch -@Name("playback-speed") -@Description("Enables the playback speed option for all videos.") -@PlaybackSpeedCompatibility -@Version("0.0.1") -class PlaybackSpeedPatch : BytecodePatch( - listOf( - SpeedControlParentFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val parentMethod = SpeedControlParentFingerprint.result!!.mutableMethod - val parentMethodInstructions = parentMethod.implementation!!.instructions - for ((index, instruction) in parentMethodInstructions.withIndex()) { - if (instruction.opcode != Opcode.INVOKE_VIRTUAL) continue - val isSpeedEnableMethod = context - .toMethodWalker(parentMethod) - .nextMethod(index, true) - .getMethod() as MutableMethod - isSpeedEnableMethod.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - break - } - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/annotations/IntegrationsCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/annotations/IntegrationsCompatibility.kt deleted file mode 100644 index e397ecf30..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/annotations/IntegrationsCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.integrations.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class IntegrationsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt deleted file mode 100644 index 9afc4eccf..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/fingerprints/InitFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.tiktok.misc.integrations.fingerprints - -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint - -object InitFingerprint : IntegrationsFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/AwemeHostApplication;") && - methodDef.name == "onCreate" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/patch/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/patch/IntegrationsPatch.kt deleted file mode 100644 index 6deed2970..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/integrations/patch/IntegrationsPatch.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.tiktok.misc.integrations.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patches.tiktok.misc.integrations.annotations.IntegrationsCompatibility -import app.revanced.patches.tiktok.misc.integrations.fingerprints.InitFingerprint -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch - -@Name("integrations") -@IntegrationsCompatibility -class IntegrationsPatch : AbstractIntegrationsPatch( - "Lapp/revanced/tiktok/utils/ReVancedUtils;", - listOf(InitFingerprint) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/annotations/DisableLoginRequirementCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/annotations/DisableLoginRequirementCompatibility.kt deleted file mode 100644 index 64acf153b..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/annotations/DisableLoginRequirementCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.disablerequirement.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DisableLoginRequirementCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt deleted file mode 100644 index 842dcae2d..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.disablerequirement.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -object MandatoryLoginServiceFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/MandatoryLoginService;") && - methodDef.name == "enableForcedLogin" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt deleted file mode 100644 index 59015a6b6..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/fingerprints/MandatoryLoginServiceFingerprint2.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.disablerequirement.fingerprints - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.tiktok.misc.login.disablerequirement.annotations.DisableLoginRequirementCompatibility - -@Name("mandatory-login-service-fingerprint2") -@DisableLoginRequirementCompatibility -@Version("0.0.1") -object MandatoryLoginServiceFingerprint2 : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/MandatoryLoginService;") && - methodDef.name == "shouldShowForcedLogin" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/patch/DisableLoginRequirementPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/patch/DisableLoginRequirementPatch.kt deleted file mode 100644 index 0967f7269..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/disablerequirement/patch/DisableLoginRequirementPatch.kt +++ /dev/null @@ -1,43 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.disablerequirement.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.tiktok.misc.login.disablerequirement.annotations.DisableLoginRequirementCompatibility -import app.revanced.patches.tiktok.misc.login.disablerequirement.fingerprints.MandatoryLoginServiceFingerprint -import app.revanced.patches.tiktok.misc.login.disablerequirement.fingerprints.MandatoryLoginServiceFingerprint2 - -@Patch -@Name("disable-login-requirement") -@Description("Do not force login.") -@DisableLoginRequirementCompatibility -@Version("0.0.1") -class DisableLoginRequirementPatch : BytecodePatch( - listOf( - MandatoryLoginServiceFingerprint, - MandatoryLoginServiceFingerprint2 - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - listOf( - MandatoryLoginServiceFingerprint, - MandatoryLoginServiceFingerprint2 - ).forEach { fingerprint -> - val method = fingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/4 v0, 0x0 - return v0 - """ - ) - } - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/annotations/FixGoogleLoginCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/annotations/FixGoogleLoginCompatibility.kt deleted file mode 100644 index 0f03b09df..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/annotations/FixGoogleLoginCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.fixgoogle.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class FixGoogleLoginCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt deleted file mode 100644 index 2e1a1eaf1..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleAuthAvailableFingerprint.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.fixgoogle.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object GoogleAuthAvailableFingerprint : MethodFingerprint( - returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf(), - customFingerprint = { methodDef -> - methodDef.definingClass == "Lcom/bytedance/lobby/google/GoogleAuth;" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt deleted file mode 100644 index 26e51a522..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/fingerprints/GoogleOneTapAuthAvailableFingerprint.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.fixgoogle.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object GoogleOneTapAuthAvailableFingerprint : MethodFingerprint( - returnType = "Z", - access = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf(), - customFingerprint = { methodDef -> - methodDef.definingClass == "Lcom/bytedance/lobby/google/GoogleOneTapAuth;" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/patch/FixGoogleLoginPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/patch/FixGoogleLoginPatch.kt deleted file mode 100644 index 9e27025c7..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/login/fixgoogle/patch/FixGoogleLoginPatch.kt +++ /dev/null @@ -1,44 +0,0 @@ -package app.revanced.patches.tiktok.misc.login.fixgoogle.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.tiktok.misc.login.fixgoogle.annotations.FixGoogleLoginCompatibility -import app.revanced.patches.tiktok.misc.login.fixgoogle.fingerprints.GoogleAuthAvailableFingerprint -import app.revanced.patches.tiktok.misc.login.fixgoogle.fingerprints.GoogleOneTapAuthAvailableFingerprint - -@Patch -@Name("fix-google-login") -@Description("Allows logging in with a Google account.") -@FixGoogleLoginCompatibility -@Version("0.0.1") -class FixGoogleLoginPatch : BytecodePatch( - listOf( - GoogleOneTapAuthAvailableFingerprint, - GoogleAuthAvailableFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - listOf( - GoogleOneTapAuthAvailableFingerprint, - GoogleAuthAvailableFingerprint - ).forEach { - with(it.result!!.mutableMethod) { - addInstructions( - 0, - """ - const/4 v0, 0x0 - return v0 - """ - ) - } - } - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/annotations/SettingsCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/annotations/SettingsCompatibility.kt deleted file mode 100644 index 8aa98d70c..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/annotations/SettingsCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SettingsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AboutViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AboutViewFingerprint.kt deleted file mode 100644 index e734a6f13..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AboutViewFingerprint.kt +++ /dev/null @@ -1,39 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -@FuzzyPatternScanMethod(4) -object AboutViewFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.MOVE, - Opcode.INVOKE_DIRECT_RANGE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.NEW_INSTANCE, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.CONST_4, - Opcode.CONST_STRING, - Opcode.INVOKE_DIRECT_RANGE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.CONST, - Opcode.SGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.CONST - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt deleted file mode 100644 index 69778a650..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/AdPersonalizationActivityOnCreateFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object AdPersonalizationActivityOnCreateFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/AdPersonalizationActivity;") && - methodDef.name == "onCreate" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt deleted file mode 100644 index 46f2ba697..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsOnViewCreatedFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SettingsOnViewCreatedFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/SettingNewVersionFragment;") && - methodDef.name == "onViewCreated" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt deleted file mode 100644 index c2f1d3c51..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/fingerprints/SettingsStatusLoadFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SettingsStatusLoadFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("Lapp/revanced/tiktok/settingsmenu/SettingsStatus;") && - methodDef.name == "load" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt deleted file mode 100644 index 0fcd0943d..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/settings/patch/SettingsPatch.kt +++ /dev/null @@ -1,120 +0,0 @@ -package app.revanced.patches.tiktok.misc.settings.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.tiktok.misc.settings.annotations.SettingsCompatibility -import app.revanced.patches.tiktok.misc.settings.fingerprints.AboutViewFingerprint -import app.revanced.patches.tiktok.misc.settings.fingerprints.AdPersonalizationActivityOnCreateFingerprint -import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsOnViewCreatedFingerprint -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.instruction.formats.Instruction35c -import org.jf.dexlib2.iface.reference.StringReference -import org.jf.dexlib2.iface.reference.TypeReference - -@Patch -@DependsOn([IntegrationsPatch::class]) -@Name("settings") -@Description("Adds ReVanced settings to TikTok.") -@SettingsCompatibility -@Version("0.0.1") -class SettingsPatch : BytecodePatch( - listOf( - AdPersonalizationActivityOnCreateFingerprint, - SettingsOnViewCreatedFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsOnViewCreatedFingerprint.result?.let { - AboutViewFingerprint.resolve(context, it.method, it.classDef) - } - // Patch Settings UI to add 'Revanced Settings'. - val targetIndexes = findOptionsOnClickIndex() - with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) { - for (index in targetIndexes) { - if ( - instruction(index).opcode != Opcode.NEW_INSTANCE || - instruction(index - 4).opcode != Opcode.MOVE_RESULT_OBJECT - ) - return PatchResultError("Hardcode offset changed.") - patchOptionNameAndOnClickEvent(index, context) - } - } - // Implement settings screen in `AdPersonalizationActivity` - with(AdPersonalizationActivityOnCreateFingerprint.result!!.mutableMethod) { - for ((index, instruction) in implementation!!.instructions.withIndex()) { - if (instruction.opcode != Opcode.INVOKE_SUPER) continue - val thisRegister = (instruction as Instruction35c).registerC - addInstructions( - index + 1, - """ - invoke-static {v$thisRegister}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->initializeSettings(Lcom/bytedance/ies/ugc/aweme/commercialize/compliance/personalization/AdPersonalizationActivity;)V - return-void - """ - ) - break - } - } - return PatchResultSuccess() - } - - private fun findOptionsOnClickIndex(): IntArray { - val results = IntArray(2) - SettingsOnViewCreatedFingerprint.result?.apply { - for ((index, instruction) in mutableMethod.implementation!!.instructions.withIndex()) { - // Old UI settings option to replace to 'Revanced Settings' - if (instruction.opcode == Opcode.CONST_STRING) { - val string = ((instruction as ReferenceInstruction).reference as StringReference).string - if (string == "copyright_policy") { - results[0] = index - 2 - break - } - } - } - - // New UI settings option to replace to 'Revanced Settings' - results[1] = AboutViewFingerprint.result!!.scanResult.patternScanResult!!.startIndex - } ?: throw SettingsOnViewCreatedFingerprint.toErrorResult() - return results - } - - private fun patchOptionNameAndOnClickEvent(index: Int, context: BytecodeContext) { - with(SettingsOnViewCreatedFingerprint.result!!.mutableMethod) { - // Patch option name - val overrideRegister = (instruction(index - 4) as OneRegisterInstruction).registerA - replaceInstruction( - index - 4, - """ - const-string v$overrideRegister, "Revanced Settings" - """ - ) - - // Patch option OnClick Event - with(((instruction(index) as ReferenceInstruction).reference as TypeReference).type) { - context.findClass(this)!!.mutableClass.methods.first { it.name == "onClick" } - .addInstructions( - 0, - """ - invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsMenu;->startSettingsActivity()V - return-void - """ - ) - } - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/annotations/SpoofSimCompatibility.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/annotations/SpoofSimCompatibility.kt deleted file mode 100644 index a775e5c13..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/annotations/SpoofSimCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.tiktok.misc.spoof.sim.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.ss.android.ugc.trill"), - Package("com.zhiliaoapp.musically") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SpoofSimCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt deleted file mode 100644 index 822a2e2fb..000000000 --- a/src/main/kotlin/app/revanced/patches/tiktok/misc/spoof/sim/patch/SpoofSimPatch.kt +++ /dev/null @@ -1,110 +0,0 @@ -package app.revanced.patches.tiktok.misc.spoof.sim.patch - -import app.revanced.extensions.findMutableMethodOf -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.tiktok.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.tiktok.misc.settings.fingerprints.SettingsStatusLoadFingerprint -import app.revanced.patches.tiktok.misc.settings.patch.SettingsPatch -import app.revanced.patches.tiktok.misc.spoof.sim.annotations.SpoofSimCompatibility -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.iface.instruction.formats.Instruction35c -import org.jf.dexlib2.iface.reference.MethodReference - -@Patch(false) -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("sim-spoof") -@Description("Spoofs the information which is retrieved from the sim-card.") -@SpoofSimCompatibility -@Version("0.0.1") -class SpoofSimPatch : BytecodePatch() { - private companion object { - val replacements = hashMapOf( - "getSimCountryIso" to "getCountryIso", - "getNetworkCountryIso" to "getCountryIso", - "getSimOperator" to "getOperator", - "getNetworkOperator" to "getOperator", - "getSimOperatorName" to "getOperatorName", - "getNetworkOperatorName" to "getOperatorName" - ) - } - - override fun execute(context: BytecodeContext): PatchResult { - // Find all api call to check sim information - buildMap { - context.classes.forEach { classDef -> - classDef.methods.let { methods -> - buildMap methodList@{ - methods.forEach methods@{ method -> - with(method.implementation?.instructions ?: return@methods) { - ArrayDeque>().also { patchIndices -> - this.forEachIndexed { index, instruction -> - if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed - - val methodRef = - (instruction as Instruction35c).reference as MethodReference - if (methodRef.definingClass != "Landroid/telephony/TelephonyManager;") return@forEachIndexed - - replacements[methodRef.name]?.let { replacement -> - patchIndices.add(index to replacement) - } - } - }.also { if (it.isEmpty()) return@methods }.let { patches -> - put(method, patches) - } - } - } - } - }.also { if (it.isEmpty()) return@forEach }.let { methodPatches -> - put(classDef, methodPatches) - } - } - }.forEach { (classDef, methods) -> - with(context.proxy(classDef).mutableClass) { - methods.forEach { (method, patches) -> - with(findMutableMethodOf(method)) { - while (!patches.isEmpty()) { - val (index, replacement) = patches.removeLast() - replaceReference(index, replacement) - } - } - } - } - } - - // Enable patch in settings - with(SettingsStatusLoadFingerprint.result!!.mutableMethod) { - addInstruction( - 0, - "invoke-static {}, Lapp/revanced/tiktok/settingsmenu/SettingsStatus;->enableSimSpoof()V" - ) - } - - return PatchResultSuccess() - } - - // Patch Android API and return fake sim information - private fun MutableMethod.replaceReference(index: Int, replacement: String) { - val resultReg = (instruction(index + 1) as OneRegisterInstruction).registerA - - addInstructions( - index + 2, - """ - invoke-static {v$resultReg}, Lapp/revanced/tiktok/spoof/sim/SpoofSimPatch;->$replacement(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$resultReg - """ - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt deleted file mode 100644 index 56bdf6286..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/fingerprints/AudioAdsPresenterPlayFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.ad.audio.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object AudioAdsPresenterPlayFingerprint : MethodFingerprint( - customFingerprint = { method -> - method.definingClass.endsWith("AudioAdsPlayerPresenter;") && method.name == "playAd" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt deleted file mode 100644 index a5cccb1c7..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/patch/AudioAdsPatch.kt +++ /dev/null @@ -1,67 +0,0 @@ -package app.revanced.patches.twitch.ad.audio.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.twitch.ad.audio.annotations.AudioAdsCompatibility -import app.revanced.patches.twitch.ad.audio.fingerprints.AudioAdsPresenterPlayFingerprint -import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("block-audio-ads") -@Description("Blocks audio ads in streams and VODs.") -@AudioAdsCompatibility -@Version("0.0.1") -class AudioAdsPatch : BytecodePatch( - listOf(AudioAdsPresenterPlayFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - // Block playAds call - with(AudioAdsPresenterPlayFingerprint.result!!) { - mutableMethod.addInstructions( - 0, - """ - invoke-static { }, Lapp/revanced/twitch/patches/AudioAdsPatch;->shouldBlockAudioAds()Z - move-result v0 - if-eqz v0, :show_audio_ads - return-void - """, - listOf(ExternalLabel("show_audio_ads", mutableMethod.instruction(0))) - ) - } - - SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( - SwitchPreference( - "revanced_block_audio_ads", - StringResource( - "revanced_block_audio_ads", - "Block audio ads" - ), - true, - StringResource( - "revanced_block_audio_ads_on", - "Audio ads are blocked" - ), - StringResource( - "revanced_block_audio_ads_off", - "Audio ads are unblocked" - ), - ) - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/annotations/EmbeddedAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/annotations/EmbeddedAdsCompatibility.kt deleted file mode 100644 index 4103c9405..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/annotations/EmbeddedAdsCompatibility.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.ad.embedded.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("tv.twitch.android.app")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class EmbeddedAdsCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt deleted file mode 100644 index 348044040..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/fingerprints/CreateUsherClientFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitch.ad.embedded.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object CreateUsherClientFingerprint : MethodFingerprint( - customFingerprint = { method -> - method.definingClass.endsWith("Ltv/twitch/android/network/OkHttpClientFactory;") && method.name == "buildOkHttpClient" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt deleted file mode 100644 index cf8f53e63..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/embedded/patch/EmbeddedAdsPatch.kt +++ /dev/null @@ -1,78 +0,0 @@ -package app.revanced.patches.twitch.ad.embedded.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.MethodFingerprintExtensions.name -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.twitch.ad.embedded.annotations.EmbeddedAdsCompatibility -import app.revanced.patches.twitch.ad.embedded.fingerprints.CreateUsherClientFingerprint -import app.revanced.patches.twitch.ad.video.patch.VideoAdsPatch -import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([VideoAdsPatch::class, IntegrationsPatch::class, SettingsPatch::class]) -@Name("block-embedded-ads") -@Description("Blocks embedded steam ads using services like TTV.lol or PurpleAdBlocker.") -@EmbeddedAdsCompatibility -@Version("0.0.1") -class EmbeddedAdsPatch : BytecodePatch( - listOf(CreateUsherClientFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - val result = CreateUsherClientFingerprint.result ?: return PatchResultError("${CreateUsherClientFingerprint.name} not found") - - // Inject OkHttp3 application interceptor - result.mutableMethod.addInstructions( - 3, - """ - invoke-static {}, Lapp/revanced/twitch/patches/EmbeddedAdsPatch;->createRequestInterceptor()Lapp/revanced/twitch/api/RequestInterceptor; - move-result-object v2 - invoke-virtual {v0, v2}, Lokhttp3/OkHttpClient${"$"}Builder;->addInterceptor(Lokhttp3/Interceptor;)Lokhttp3/OkHttpClient${"$"}Builder; - """ - ) - - SettingsPatch.PreferenceScreen.ADS.SURESTREAM.addPreferences( - ListPreference( - "revanced_block_embedded_ads", - StringResource( - "revanced_block_embedded_ads", - "Block embedded video ads" - ), - ArrayResource( - "revanced_hls_proxies", - listOf( - StringResource("revanced_proxy_disabled", "Disabled"), - StringResource("revanced_proxy_ttv_lol", "TTV LOL proxy"), - StringResource("revanced_proxy_purpleadblock", "PurpleAdBlock proxy"), - ) - ), - ArrayResource( - "revanced_hls_proxies_values", - listOf( - StringResource("key_revanced_proxy_disabled", "disabled"), - StringResource("key_revanced_proxy_ttv_lol", "ttv-lol"), - StringResource("key_revanced_proxy_purpleadblock", "purpleadblock") - ) - ), - "ttv-lol" - ) - ) - - SettingsPatch.addString("revanced_embedded_ads_service_unavailable", "%s is unavailable. Ads may show. Try switching to another ad block service in settings.") - SettingsPatch.addString("revanced_embedded_ads_service_failed", "%s server returned an error. Ads may show. Try switching to another ad block service in settings.") - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch.kt deleted file mode 100644 index dca265bc7..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/shared/util/AbstractAdPatch.kt +++ /dev/null @@ -1,51 +0,0 @@ -package app.revanced.patches.twitch.ad.shared.util - -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.util.smali.ExternalLabel - -abstract class AbstractAdPatch( - val conditionCall: String, - val skipLabelName: String, - internal val fingerprints: Iterable? = null, -) : BytecodePatch(fingerprints) { - - protected fun createConditionInstructions(register: String = "v0") = """ - invoke-static { }, $conditionCall - move-result $register - if-eqz $register, :$skipLabelName - """ - - protected data class ReturnMethod(val returnType: Char = 'V', val value: String = "") - - protected fun BytecodeContext.blockMethods(clazz: String, vararg methodNames: String, returnMethod: ReturnMethod = ReturnMethod()): Boolean { - - return with(findClass(clazz)?.mutableClass) { - this ?: return false - - this.methods.filter { methodNames.contains(it.name) }.forEach { - val retIntructions = when(returnMethod.returnType) { - 'V' -> "return-void" - 'Z' -> """ - const/4 v0, ${returnMethod.value} - return v0 - """ - else -> throw NotImplementedError() - } - it.addInstructions( - 0, - """ - ${createConditionInstructions("v0")} - $retIntructions - """, - listOf(ExternalLabel(skipLabelName, it.instruction(0))) - ) - } - true - } - } - -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/annotations/VideoAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/annotations/VideoAdsCompatibility.kt deleted file mode 100644 index 60c4d169c..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/annotations/VideoAdsCompatibility.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.ad.video.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("tv.twitch.android.app")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class VideoAdsCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt deleted file mode 100644 index 04c1c09b1..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/CheckAdEligibilityLambdaFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.twitch.ad.video.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object CheckAdEligibilityLambdaFingerprint : MethodFingerprint( - "L", - AccessFlags.PRIVATE or AccessFlags.FINAL or AccessFlags.STATIC, - listOf("L", "L", "L"), - customFingerprint = { method -> - method.definingClass.endsWith("AdEligibilityFetcher;") && - method.name.contains("shouldRequestAd") - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt deleted file mode 100644 index ed38035eb..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/ContentConfigShowAdsFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.ad.video.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object ContentConfigShowAdsFingerprint : MethodFingerprint( - customFingerprint = { method -> - method.definingClass.endsWith("ContentConfigData;") && method.name == "getShowAds" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt deleted file mode 100644 index 3256ad024..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/fingerprints/GetReadyToShowAdFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitch.ad.video.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object GetReadyToShowAdFingerprint : MethodFingerprint( - customFingerprint = { method -> - method.definingClass.endsWith("/StreamDisplayAdsPresenter;") && method.name == "getReadyToShowAdOrAbort" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt deleted file mode 100644 index 9b1197e78..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/video/patch/VideoAdsPatch.kt +++ /dev/null @@ -1,149 +0,0 @@ -package app.revanced.patches.twitch.ad.video.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.twitch.ad.shared.util.AbstractAdPatch -import app.revanced.patches.twitch.ad.video.annotations.VideoAdsCompatibility -import app.revanced.patches.twitch.ad.video.fingerprints.CheckAdEligibilityLambdaFingerprint -import app.revanced.patches.twitch.ad.video.fingerprints.ContentConfigShowAdsFingerprint -import app.revanced.patches.twitch.ad.video.fingerprints.GetReadyToShowAdFingerprint -import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("block-video-ads") -@Description("Blocks video ads in streams and VODs.") -@VideoAdsCompatibility -@Version("0.0.1") -class VideoAdsPatch : AbstractAdPatch( - "Lapp/revanced/twitch/patches/VideoAdsPatch;->shouldBlockVideoAds()Z", - "show_video_ads", - listOf( - ContentConfigShowAdsFingerprint, - CheckAdEligibilityLambdaFingerprint, - GetReadyToShowAdFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - /* Amazon ads SDK */ - context.blockMethods( - "Lcom/amazon/ads/video/player/AdsManagerImpl;", - "playAds" - ) - - /* Twitch ads manager */ - context.blockMethods( - "Ltv/twitch/android/shared/ads/VideoAdManager;", - "checkAdEligibilityAndRequestAd", "requestAd", "requestAds" - ) - - /* Various ad presenters */ - context.blockMethods( - "Ltv/twitch/android/shared/ads/AdsPlayerPresenter;", - "requestAd", "requestFirstAd", "requestFirstAdIfEligible", "requestMidroll", "requestAdFromMultiAdFormatEvent" - ) - - context.blockMethods( - "Ltv/twitch/android/shared/ads/AdsVodPlayerPresenter;", - "requestAd", "requestFirstAd", - ) - - context.blockMethods( - "Ltv/twitch/android/feature/theatre/ads/AdEdgeAllocationPresenter;", - "parseAdAndCheckEligibility", "requestAdsAfterEligibilityCheck", "showAd", "bindMultiAdFormatAllocation" - ) - - /* A/B ad testing experiments */ - context.blockMethods( - "Ltv/twitch/android/provider/experiments/helpers/DisplayAdsExperimentHelper;", - "areDisplayAdsEnabled", - returnMethod = ReturnMethod('Z', "0") - ) - - context.blockMethods( - "Ltv/twitch/android/shared/ads/tracking/MultiFormatAdsTrackingExperiment;", - "shouldUseMultiAdFormatTracker", "shouldUseVideoAdTracker", - returnMethod = ReturnMethod('Z', "0") - ) - - context.blockMethods( - "Ltv/twitch/android/shared/ads/MultiformatAdsExperiment;", - "shouldDisableClientSideLivePreroll", "shouldDisableClientSideVodPreroll", - returnMethod = ReturnMethod('Z', "1") - ) - - // Pretend our player is ineligible for all ads - with(CheckAdEligibilityLambdaFingerprint.result!!) { - mutableMethod.addInstructions( - 0, - """ - ${createConditionInstructions()} - const/4 v0, 0 - invoke-static {v0}, Lio/reactivex/Single;->just(Ljava/lang/Object;)Lio/reactivex/Single; - move-result-object p0 - return-object p0 - """, - listOf(ExternalLabel(skipLabelName, mutableMethod.instruction(0))) - ) - } - - with(GetReadyToShowAdFingerprint.result!!) { - val adFormatDeclined = "Ltv/twitch/android/shared/display/ads/theatre/StreamDisplayAdsPresenter\$Action\$AdFormatDeclined;" - mutableMethod.addInstructions( - 0, - """ - ${createConditionInstructions()} - sget-object p2, $adFormatDeclined->INSTANCE:$adFormatDeclined - invoke-static {p1, p2}, Ltv/twitch/android/core/mvp/presenter/StateMachineKt;->plus(Ltv/twitch/android/core/mvp/presenter/PresenterState;Ltv/twitch/android/core/mvp/presenter/PresenterAction;)Ltv/twitch/android/core/mvp/presenter/StateAndAction; - move-result-object p1 - return-object p1 - """, - listOf(ExternalLabel(skipLabelName, mutableMethod.instruction(0))) - ) - } - - // Spoof showAds JSON field - with(ContentConfigShowAdsFingerprint.result!!) { - mutableMethod.addInstructions(0, """ - ${createConditionInstructions()} - const/4 v0, 0 - :$skipLabelName - return v0 - """ - ) - } - - SettingsPatch.PreferenceScreen.ADS.CLIENT_SIDE.addPreferences( - SwitchPreference( - "revanced_block_video_ads", - StringResource( - "revanced_block_video_ads", - "Block video ads" - ), - true, - StringResource( - "revanced_block_video_ads_on", - "Video ads are blocked" - ), - StringResource( - "revanced_block_video_ads_off", - "Video ads are unblocked" - ), - ) - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/annotations/ShowDeletedMessagesCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/annotations/ShowDeletedMessagesCompatibility.kt deleted file mode 100644 index c0c71beaa..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/annotations/ShowDeletedMessagesCompatibility.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.chat.antidelete.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("tv.twitch.android.app")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ShowDeletedMessagesCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt deleted file mode 100644 index 733710b2b..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/ChatUtilCreateDeletedSpanFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitch.chat.antidelete.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object ChatUtilCreateDeletedSpanFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/ChatUtil\$Companion;") && methodDef.name == "createDeletedSpanFromChatMessageSpan" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt deleted file mode 100644 index 6ecb63cbd..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/DeletedMessageClickableSpanCtorFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.twitch.chat.antidelete.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object DeletedMessageClickableSpanCtorFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("DeletedMessageClickableSpan;") - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt deleted file mode 100644 index 7e8ee66a3..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/fingerprints/SetHasModAccessFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.chat.antidelete.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SetHasModAccessFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("DeletedMessageClickableSpan;") && methodDef.name == "setHasModAccess" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt deleted file mode 100644 index dba6e833e..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/chat/antidelete/patch/ShowDeletedMessagesPatch.kt +++ /dev/null @@ -1,103 +0,0 @@ -package app.revanced.patches.twitch.chat.antidelete.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.* -import app.revanced.patcher.patch.* -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.ListPreference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.twitch.chat.antidelete.annotations.ShowDeletedMessagesCompatibility -import app.revanced.patches.twitch.chat.antidelete.fingerprints.* -import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("show-deleted-messages") -@Description("Shows deleted chat messages behind a clickable spoiler.") -@ShowDeletedMessagesCompatibility -@Version("0.0.1") -class ShowDeletedMessagesPatch : BytecodePatch( - listOf( - SetHasModAccessFingerprint, - DeletedMessageClickableSpanCtorFingerprint, - ChatUtilCreateDeletedSpanFingerprint - ) -) { - private fun createSpoilerConditionInstructions(register: String = "v0") = """ - invoke-static {}, Lapp/revanced/twitch/patches/ShowDeletedMessagesPatch;->shouldUseSpoiler()Z - move-result $register - if-eqz $register, :no_spoiler - """ - - override fun execute(context: BytecodeContext): PatchResult { - // Spoiler mode: Force set hasModAccess member to true in constructor - with(DeletedMessageClickableSpanCtorFingerprint.result!!.mutableMethod) { - addInstructions( - implementation!!.instructions.lastIndex, /* place in front of return-void */ - """ - ${createSpoilerConditionInstructions()} - const/4 v0, 1 - iput-boolean v0, p0, $definingClass->hasModAccess:Z - """, - listOf(ExternalLabel("no_spoiler", instruction(implementation!!.instructions.lastIndex))) - ) - } - - // Spoiler mode: Disable setHasModAccess setter - with(SetHasModAccessFingerprint.result!!) { - mutableMethod.addInstruction(0, "return-void") - } - - // Cross-out mode: Reformat span of deleted message - with(ChatUtilCreateDeletedSpanFingerprint.result!!) { - mutableMethod.addInstructions( - 0, - """ - invoke-static {p2}, Lapp/revanced/twitch/patches/ShowDeletedMessagesPatch;->reformatDeletedMessage(Landroid/text/Spanned;)Landroid/text/Spanned; - move-result-object v0 - if-eqz v0, :no_reformat - return-object v0 - """, - listOf(ExternalLabel("no_reformat", mutableMethod.instruction(0))) - ) - } - - SettingsPatch.PreferenceScreen.CHAT.GENERAL.addPreferences( - ListPreference( - "revanced_show_deleted_messages", - StringResource( - "revanced_show_deleted_messages_title", - "Show deleted messages" - ), - ArrayResource( - "revanced_deleted_messages", - listOf( - StringResource("revanced_deleted_messages_hide", "Do not show deleted messages"), - StringResource("revanced_deleted_messages_spoiler", "Hide deleted messages behind a spoiler"), - StringResource("revanced_deleted_messages_cross_out", "Show deleted messages as crossed-out text") - ) - ), - ArrayResource( - "revanced_deleted_messages_values", - listOf( - StringResource("key_revanced_deleted_messages_hide", "hide"), - StringResource("key_revanced_deleted_messages_spoiler", "spoiler"), - StringResource("key_revanced_deleted_messages_cross_out", "cross-out") - ) - ), - "cross-out" - ) - ) - - SettingsPatch.addString("revanced_deleted_msg", "message deleted") - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/annotations/DebugModeCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/annotations/DebugModeCompatibility.kt deleted file mode 100644 index 394b9e904..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/annotations/DebugModeCompatibility.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.debug.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("tv.twitch.android.app")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DebugModeCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt deleted file mode 100644 index e7a317849..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsDebugConfigEnabledFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.debug.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object IsDebugConfigEnabledFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "isDebugConfigEnabled" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt deleted file mode 100644 index cf8f1f759..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/IsOmVerificationEnabledFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.debug.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object IsOmVerificationEnabledFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "isOmVerificationEnabled" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt deleted file mode 100644 index 12c5de043..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/fingerprints/ShouldShowDebugOptionsFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.debug.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object ShouldShowDebugOptionsFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("BuildConfigUtil;") && methodDef.name == "shouldShowDebugOptions" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt b/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt deleted file mode 100644 index 755efe696..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/debug/patch/DebugModePatch.kt +++ /dev/null @@ -1,76 +0,0 @@ -package app.revanced.patches.twitch.debug.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.twitch.debug.annotations.DebugModeCompatibility -import app.revanced.patches.twitch.debug.fingerprints.IsDebugConfigEnabledFingerprint -import app.revanced.patches.twitch.debug.fingerprints.IsOmVerificationEnabledFingerprint -import app.revanced.patches.twitch.debug.fingerprints.ShouldShowDebugOptionsFingerprint -import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.twitch.misc.settings.bytecode.patch.SettingsPatch - -@Patch(false) -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("debug-mode") -@Description("Enables Twitch's internal debugging mode.") -@DebugModeCompatibility -@Version("0.0.1") -class DebugModePatch : BytecodePatch( - listOf( - IsDebugConfigEnabledFingerprint, - IsOmVerificationEnabledFingerprint, - ShouldShowDebugOptionsFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - listOf( - IsDebugConfigEnabledFingerprint, - IsOmVerificationEnabledFingerprint, - ShouldShowDebugOptionsFingerprint - ).forEach { - with(it.result!!) { - with(mutableMethod) { - addInstructions( - 0, - """ - invoke-static {}, Lapp/revanced/twitch/patches/DebugModePatch;->isDebugModeEnabled()Z - move-result v0 - return v0 - """ - ) - } - } - } - - SettingsPatch.PreferenceScreen.MISC.OTHER.addPreferences( - SwitchPreference( - "revanced_debug_mode", - StringResource( - "revanced_debug_mode_enable", - "Enable debug mode" - ), - false, - StringResource( - "revanced_debug_mode_on", - "Debug mode is enabled (not recommended)" - ), - StringResource( - "revanced_debug_mode_off", - "Debug mode is disabled" - ), - ) - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/annotations/IntegrationsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/annotations/IntegrationsCompatibility.kt deleted file mode 100644 index f0e219fbd..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/annotations/IntegrationsCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitch.misc.integrations.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("tv.twitch.android.app")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class IntegrationsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt deleted file mode 100644 index 7f55dd22f..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/fingerprints/InitFingerprint.kt +++ /dev/null @@ -1,16 +0,0 @@ -package app.revanced.patches.twitch.misc.integrations.fingerprints - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patches.twitch.misc.integrations.annotations.IntegrationsCompatibility -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint - -@Name("init-fingerprint") -@IntegrationsCompatibility -@Version("0.0.1") -object InitFingerprint : IntegrationsFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/TwitchApplication;") && - methodDef.name == "onCreate" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/patch/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/patch/IntegrationsPatch.kt deleted file mode 100644 index 027106d88..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/integrations/patch/IntegrationsPatch.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.twitch.misc.integrations.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patches.twitch.misc.integrations.fingerprints.InitFingerprint -import app.revanced.patches.twitch.misc.integrations.annotations.IntegrationsCompatibility -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch - -@Name("integrations") -@IntegrationsCompatibility -class IntegrationsPatch : AbstractIntegrationsPatch( - "Lapp/revanced/twitch/utils/ReVancedUtils;", - listOf(InitFingerprint) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/annotations/SettingsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/annotations/SettingsCompatibility.kt deleted file mode 100644 index 0eadf6909..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/annotations/SettingsCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("tv.twitch.android.app")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SettingsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt deleted file mode 100644 index d0f8b7214..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/bytecode/patch/SettingsPatch.kt +++ /dev/null @@ -1,196 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.* -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.PreferenceCategory -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen -import app.revanced.patches.twitch.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.twitch.misc.settings.annotations.SettingsCompatibility -import app.revanced.patches.twitch.misc.settings.components.CustomPreferenceCategory -import app.revanced.patches.twitch.misc.settings.fingerprints.* -import app.revanced.patches.twitch.misc.settings.resource.patch.SettingsResourcePatch -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.immutable.ImmutableField - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsResourcePatch::class]) -@Name("settings") -@Description("Adds settings menu to Twitch.") -@SettingsCompatibility -@Version("0.0.1") -class SettingsPatch : BytecodePatch( - listOf( - SettingsActivityOnCreateFingerprint, - SettingsMenuItemEnumFingerprint, - MenuGroupsUpdatedFingerprint, - MenuGroupsOnClickFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - // Hook onCreate to handle fragment creation - with(SettingsActivityOnCreateFingerprint.result!!) { - val insertIndex = mutableMethod.implementation!!.instructions.size - 2 - mutableMethod.addInstructions( - insertIndex, - """ - invoke-static {p0}, $SETTINGS_HOOKS_CLASS->handleSettingsCreation(Landroidx/appcompat/app/AppCompatActivity;)Z - move-result v0 - if-eqz v0, :no_rv_settings_init - return-void - """, - listOf(ExternalLabel("no_rv_settings_init", mutableMethod.instruction(insertIndex))) - ) - } - - // Create new menu item for settings menu - with(SettingsMenuItemEnumFingerprint.result!!) { - injectMenuItem( - REVANCED_SETTINGS_MENU_ITEM_NAME, - REVANCED_SETTINGS_MENU_ITEM_ID, - REVANCED_SETTINGS_MENU_ITEM_TITLE_RES, - REVANCED_SETTINGS_MENU_ITEM_ICON_RES - ) - } - - // Intercept settings menu creation and add new menu item - with(MenuGroupsUpdatedFingerprint.result!!) { - mutableMethod.addInstructions( - 0, - """ - sget-object v0, $MENU_ITEM_ENUM_CLASS->$REVANCED_SETTINGS_MENU_ITEM_NAME:$MENU_ITEM_ENUM_CLASS - invoke-static {p1, v0}, $SETTINGS_HOOKS_CLASS->handleSettingMenuCreation(Ljava/util/List;Ljava/lang/Object;)Ljava/util/List; - move-result-object p1 - """ - ) - } - - // Intercept onclick events for the settings menu - with(MenuGroupsOnClickFingerprint.result!!) { - val insertIndex = 0 - mutableMethod.addInstructions( - insertIndex, - """ - invoke-static {p1}, $SETTINGS_HOOKS_CLASS->handleSettingMenuOnClick(Ljava/lang/Enum;)Z - move-result p2 - if-eqz p2, :no_rv_settings_onclick - sget-object p1, $MENU_DISMISS_EVENT_CLASS->INSTANCE:$MENU_DISMISS_EVENT_CLASS - invoke-virtual {p0, p1}, Ltv/twitch/android/core/mvp/viewdelegate/RxViewDelegate;->pushEvent(Ltv/twitch/android/core/mvp/viewdelegate/ViewDelegateEvent;)V - return-void - """, - listOf(ExternalLabel("no_rv_settings_onclick", mutableMethod.instruction(insertIndex))) - ) - } - - addString("revanced_settings", "ReVanced Settings", false) - addString("revanced_reboot_message", "Twitch needs to restart to apply your changes. Restart now?", false) - addString("revanced_reboot", "Restart", false) - addString("revanced_cancel", "Cancel", false) - - return PatchResultSuccess() - } - - internal companion object { - fun addString(identifier: String, value: String, formatted: Boolean = true) = - SettingsResourcePatch.addString(identifier, value, formatted) - - fun addPreferenceScreen(preferenceScreen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) = - SettingsResourcePatch.addPreferenceScreen(preferenceScreen) - - /* Private members */ - private const val REVANCED_SETTINGS_MENU_ITEM_NAME = "RevancedSettings" - private const val REVANCED_SETTINGS_MENU_ITEM_ID = 0x7 - private const val REVANCED_SETTINGS_MENU_ITEM_TITLE_RES = "revanced_settings" - private const val REVANCED_SETTINGS_MENU_ITEM_ICON_RES = "ic_settings" - - private const val MENU_ITEM_ENUM_CLASS = "Ltv/twitch/android/feature/settings/menu/SettingsMenuItem;" - private const val MENU_DISMISS_EVENT_CLASS = "Ltv/twitch/android/feature/settings/menu/SettingsMenuViewDelegate\$Event\$OnDismissClicked;" - - private const val INTEGRATIONS_PACKAGE = "app/revanced/twitch" - private const val SETTINGS_HOOKS_CLASS = "L$INTEGRATIONS_PACKAGE/settingsmenu/SettingsHooks;" - private const val REVANCED_UTILS_CLASS = "L$INTEGRATIONS_PACKAGE/utils/ReVancedUtils;" - - private fun MethodFingerprintResult.injectMenuItem( - name: String, - value: Int, - titleResourceName: String, - iconResourceName: String - ) { - // Add new static enum member field - mutableClass.staticFields.add( - ImmutableField( - mutableMethod.definingClass, - name, - MENU_ITEM_ENUM_CLASS, - AccessFlags.PUBLIC or AccessFlags.FINAL or AccessFlags.ENUM or AccessFlags.STATIC, - null, - null, - null - ).toMutable() - ) - - // Add initializer for the new enum member - mutableMethod.addInstructions( - mutableMethod.implementation!!.instructions.size - 4, - """ - new-instance v0, $MENU_ITEM_ENUM_CLASS - const-string v1, "$titleResourceName" - invoke-static {v1}, $REVANCED_UTILS_CLASS->getStringId(Ljava/lang/String;)I - move-result v1 - const-string v3, "$iconResourceName" - invoke-static {v3}, $REVANCED_UTILS_CLASS->getDrawableId(Ljava/lang/String;)I - move-result v3 - const-string v4, "$name" - const/4 v5, $value - invoke-direct {v0, v4, v5, v1, v3}, $MENU_ITEM_ENUM_CLASS->(Ljava/lang/String;III)V - sput-object v0, $MENU_ITEM_ENUM_CLASS->$name:$MENU_ITEM_ENUM_CLASS - """ - ) - } - } - - /** - * Preference screens patches should add their settings to. - */ - internal object PreferenceScreen : AbstractPreferenceScreen() { - val ADS = CustomScreen("ads", "Ads", "Ad blocking settings") - val CHAT = CustomScreen("chat", "Chat", "Chat settings") - val MISC = CustomScreen("misc", "Misc", "Miscellaneous patches") - - internal class CustomScreen(key: String, title: String, summary: String) : Screen(key, title, summary) { - /* Categories */ - val GENERAL = CustomCategory("general", "General settings") - val OTHER = CustomCategory("other", "Other settings") - val CLIENT_SIDE = CustomCategory("client_ads", "Client-side ads") - val SURESTREAM = CustomCategory("surestream_ads", "Server-side surestream ads") - - internal inner class CustomCategory(key: String, title: String) : Screen.Category(key, title) { - /* For Twitch, we need to load our CustomPreferenceCategory class instead of the default one. */ - override fun transform(): PreferenceCategory { - return CustomPreferenceCategory( - key, - StringResource("${key}_title", title), - preferences.sortedBy { it.title.value } - ) - } - } - } - - override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) { - addPreferenceScreen(screen) - } - } - - override fun close() = PreferenceScreen.close() -} diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/components/CustomPreferenceCategory.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/components/CustomPreferenceCategory.kt deleted file mode 100644 index 20c7bdb80..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/components/CustomPreferenceCategory.kt +++ /dev/null @@ -1,20 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.components - -import app.revanced.patches.shared.settings.preference.BasePreference -import app.revanced.patches.shared.settings.preference.impl.PreferenceCategory -import app.revanced.patches.shared.settings.preference.impl.StringResource - -/** - * Customized preference category for Twitch. - * - * @param key The key of the preference. - * @param title The title of the preference. - * @param preferences Child preferences of this category. - */ -internal open class CustomPreferenceCategory( - key: String, - title: StringResource, - preferences: List -) : PreferenceCategory(key, title, preferences) { - override val tag: String = "app.revanced.twitch.settingsmenu.preference.CustomPreferenceCategory" -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt deleted file mode 100644 index 1a6375986..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsOnClickFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object MenuGroupsOnClickFingerprint : MethodFingerprint( - "V", - AccessFlags.PRIVATE or AccessFlags.STATIC or AccessFlags.FINAL, - listOf("L", "L", "L"), - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/SettingsMenuViewDelegate;") - && methodDef.name.contains("render") - } -) diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt deleted file mode 100644 index 913f31d14..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/MenuGroupsUpdatedFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object MenuGroupsUpdatedFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/SettingsMenuPresenter\$Event\$MenuGroupsUpdated;") - && methodDef.name == "" - } -) diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt deleted file mode 100644 index f976f0210..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsActivityOnCreateFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SettingsActivityOnCreateFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/SettingsActivity;") && - methodDef.name == "onCreate" - } -) diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt deleted file mode 100644 index cdb2dd177..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/fingerprints/SettingsMenuItemEnumFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object SettingsMenuItemEnumFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("/SettingsMenuItem;") && methodDef.name == "" - } -) diff --git a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/resource/patch/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/twitch/misc/settings/resource/patch/SettingsResourcePatch.kt deleted file mode 100644 index 07420cea9..000000000 --- a/src/main/kotlin/app/revanced/patches/twitch/misc/settings/resource/patch/SettingsResourcePatch.kt +++ /dev/null @@ -1,44 +0,0 @@ -package app.revanced.patches.twitch.misc.settings.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.resource.patch.AbstractSettingsResourcePatch -import app.revanced.patches.twitch.misc.settings.annotations.SettingsCompatibility - -@Name("settings-resource-patch") -@SettingsCompatibility -@Version("0.0.1") -class SettingsResourcePatch : AbstractSettingsResourcePatch( -"revanced_prefs", -"twitch/settings" -) { - internal companion object { - /* Companion delegates */ - - /** - * 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) = - AbstractSettingsResourcePatch.addString(identifier, value, formatted) - - /** - * Add an array to the resources. - * - * @param arrayResource The array resource to add. - */ - fun addArray(arrayResource: ArrayResource) = AbstractSettingsResourcePatch.addArray(arrayResource) - - /** - * Add a preference to the settings. - * - * @param preferenceScreen The name of the preference screen. - */ - fun addPreferenceScreen(preferenceScreen: PreferenceScreen) = AbstractSettingsResourcePatch.addPreference(preferenceScreen) - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/annotations/TimelineAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/annotations/TimelineAdsCompatibility.kt deleted file mode 100644 index 54ce87619..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/annotations/TimelineAdsCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitter.ad.timeline.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.twitter.android")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class TimelineAdsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/fingerprints/TimelineTweetJsonParserFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/fingerprints/TimelineTweetJsonParserFingerprint.kt deleted file mode 100644 index 5d4b98732..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/fingerprints/TimelineTweetJsonParserFingerprint.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.twitter.ad.timeline.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object TimelineTweetJsonParserFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.IPUT_OBJECT, - Opcode.GOTO, - Opcode.SGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.IPUT_OBJECT, - Opcode.RETURN_VOID, - ), strings = listOf("tweetPromotedMetadata", "promotedMetadata", "hasModeratedReplies", "conversationAnnotation"), - customFingerprint = { methodDef -> methodDef.name == "parseField" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/patch/TimelineAdsPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/patch/TimelineAdsPatch.kt deleted file mode 100644 index 753a2ea05..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/ad/timeline/patch/TimelineAdsPatch.kt +++ /dev/null @@ -1,77 +0,0 @@ -package app.revanced.patches.twitter.ad.timeline.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.twitter.ad.timeline.annotations.TimelineAdsCompatibility -import app.revanced.patches.twitter.ad.timeline.fingerprints.TimelineTweetJsonParserFingerprint -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.BuilderInstruction -import org.jf.dexlib2.builder.instruction.BuilderInstruction22c -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.FieldReference -import org.jf.dexlib2.iface.reference.StringReference - -@Patch -@Name("timeline-ads") -@Description("Removes ads from the Twitter timeline. Might require clearing app data to remove already cached ads.") -@TimelineAdsCompatibility -@Version("0.0.1") -class TimelineAdsPatch : BytecodePatch( - listOf(TimelineTweetJsonParserFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - if (removePromotedAds()) - return PatchResultError("The instruction for the tweet id field could not be found") - - return PatchResultSuccess() - } - - private fun removePromotedAds(): Boolean { - val (parserFingerprintResult, parserMethod, instructions) = TimelineTweetJsonParserFingerprint.unwrap() - - // Anchor index - val tweetIdFieldInstructionIndex = instructions.indexOfFirst { instruction -> - if (instruction.opcode.ordinal != Opcode.CONST_STRING.ordinal) return@indexOfFirst false - if (((instruction as? ReferenceInstruction)?.reference as StringReference).string != "tweetSocialProof") return@indexOfFirst false - - // Use the above conditions as an anchor to find the index for the instruction with the field we need - return@indexOfFirst true - } - 2 // This is where the instruction with the field is located - - // Reference to the tweetId field for of the timeline tweet - val tweetIdFieldReference = - (parserMethod.instruction(tweetIdFieldInstructionIndex) as? BuilderInstruction22c)?.reference as? FieldReference - ?: return true - - // Set the tweetId field to null - // This will cause twitter to not show the promoted ads, because we set it to null, when the tweet is promoted - parserFingerprintResult.mutableMethod.addInstructions( - parserFingerprintResult.scanResult.patternScanResult!!.startIndex + 1, - """ - const/4 v2, 0x0 - iput-object v2, p0, Lcom/twitter/model/json/timeline/urt/JsonTimelineTweet;->${tweetIdFieldReference.name}:Ljava/lang/String; - """ - ) - return false - } - - private fun MethodFingerprint.unwrap(): Triple> { - val parserFingerprintResult = this.result!! - val parserMethod = parserFingerprintResult.mutableMethod - val instructions = parserMethod.implementation!!.instructions - - return Triple(parserFingerprintResult, parserMethod, instructions) - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/annotations/DynamicColorCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/annotations/DynamicColorCompatibility.kt deleted file mode 100644 index 135276a1c..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/annotations/DynamicColorCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitter.misc.dynamiccolor.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.twitter.android")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DynamicColorCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/patch/DynamicColorPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/patch/DynamicColorPatch.kt deleted file mode 100644 index 3ba3b564c..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/dynamiccolor/patch/DynamicColorPatch.kt +++ /dev/null @@ -1,87 +0,0 @@ -package app.revanced.patches.twitter.misc.dynamiccolor.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.twitter.misc.dynamiccolor.annotations.DynamicColorCompatibility -import java.io.FileWriter -import java.nio.file.Files - -@Patch -@Name("dynamic-color") -@Description("Replaces the default Twitter Blue with the users Material You palette.") -@DynamicColorCompatibility -@Version("0.0.1") -class DynamicColorPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - val resDirectory = context["res"] - if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.") - - val valuesV31Directory = resDirectory.resolve("values-v31") - if (!valuesV31Directory.isDirectory) Files.createDirectories(valuesV31Directory.toPath()) - - val valuesNightV31Directory = resDirectory.resolve("values-night-v31") - if (!valuesNightV31Directory.isDirectory) Files.createDirectories(valuesNightV31Directory.toPath()) - - listOf(valuesV31Directory, valuesNightV31Directory).forEach { it -> - val colorsXml = it.resolve("colors.xml") - - if(!colorsXml.exists()) { - FileWriter(colorsXml).use { - it.write("") - } - } - } - - context.xmlEditor["res/values-v31/colors.xml"].use { editor -> - val document = editor.file - - mapOf( - "ps__twitter_blue" to "@color/twitter_blue", - "ps__twitter_blue_pressed" to "@color/twitter_blue_fill_pressed", - "twitter_blue" to "@android:color/system_accent1_400", - "twitter_blue_fill_pressed" to "@android:color/system_accent1_300", - "twitter_blue_opacity_30" to "@android:color/system_accent1_100", - "twitter_blue_opacity_50" to "@android:color/system_accent1_200", - "twitter_blue_opacity_58" to "@android:color/system_accent1_300", - "deep_transparent_twitter_blue" to "@android:color/system_accent1_200", - "ic_launcher_background" to "#1DA1F2" - ).forEach { (k, v) -> - val colorElement = document.createElement("color") - - colorElement.setAttribute("name", k) - colorElement.textContent = v - - document.getElementsByTagName("resources").item(0).appendChild(colorElement) - } - } - - context.xmlEditor["res/values-night-v31/colors.xml"].use { editor -> - val document = editor.file - - mapOf( - "twitter_blue" to "@android:color/system_accent1_200", - "twitter_blue_fill_pressed" to "@android:color/system_accent1_300", - "twitter_blue_opacity_30" to "@android:color/system_accent1_50", - "twitter_blue_opacity_50" to "@android:color/system_accent1_100", - "twitter_blue_opacity_58" to "@android:color/system_accent1_200", - "deep_transparent_twitter_blue" to "@android:color/system_accent1_200" - ).forEach { (k, v) -> - val colorElement = document.createElement("color") - - colorElement.setAttribute("name", k) - colorElement.textContent = v - - document.getElementsByTagName("resources").item(0).appendChild(colorElement) - } - } - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/monochrome/annotations/MonochromeIconCompatibility.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/monochrome/annotations/MonochromeIconCompatibility.kt deleted file mode 100644 index 646ad2b0b..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/monochrome/annotations/MonochromeIconCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.twitter.misc.monochrome.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.twitter.android")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MonochromeIconCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/twitter/misc/monochrome/patch/MonochromeIconPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/misc/monochrome/patch/MonochromeIconPatch.kt deleted file mode 100644 index 6e83ca519..000000000 --- a/src/main/kotlin/app/revanced/patches/twitter/misc/monochrome/patch/MonochromeIconPatch.kt +++ /dev/null @@ -1,55 +0,0 @@ -package app.revanced.patches.twitter.misc.monochrome.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.twitter.misc.monochrome.annotations.MonochromeIconCompatibility -import java.io.FileWriter -import java.nio.file.Files - -@Patch -@Name("monochrome-icon") -@Description("Adds a monochrome icon.") -@MonochromeIconCompatibility -@Version("0.0.1") -class MonochromeIconPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - val resDirectory = context["res"] - if (!resDirectory.isDirectory) return PatchResultError("The res folder can not be found.") - - val mipmapV33Directory = resDirectory.resolve("mipmap-anydpi-v33") - if (!mipmapV33Directory.isDirectory) Files.createDirectories(mipmapV33Directory.toPath()) - - FileWriter(mipmapV33Directory.resolve("ic_launcher_twitter.xml")).use { - it.write( - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - "" - ) - } - - FileWriter(mipmapV33Directory.resolve("ic_launcher_twitter_round.xml")).use { - it.write( - "\n" + - "\n" + - " \n" + - " \n" + - " \n" + - "" - ) - } - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/annotations/FirebaseGetCertPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/annotations/FirebaseGetCertPatchCompatibility.kt deleted file mode 100644 index a87fa5336..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/annotations/FirebaseGetCertPatchCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.warnwetter.misc.firebasegetcert.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("de.dwd.warnapp")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class FirebaseGetCertPatchCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/fingerprints/GetCertMessagingFingerprint.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/fingerprints/GetCertMessagingFingerprint.kt deleted file mode 100644 index 196f649cf..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/fingerprints/GetCertMessagingFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object GetMessagingCertFingerprint : MethodFingerprint( - "Ljava/lang/String;", - strings = listOf( - "ContentValues", - "Could not get fingerprint hash for package: ", - "No such package: " - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/fingerprints/GetCertRegistrationFingerprint.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/fingerprints/GetCertRegistrationFingerprint.kt deleted file mode 100644 index 8c1fb8c55..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/fingerprints/GetCertRegistrationFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object GetReqistrationCertFingerprint : MethodFingerprint( - "Ljava/lang/String;", - strings = listOf( - "FirebaseRemoteConfig", - "Could not get fingerprint hash for package: ", - "No such package: " - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/patch/FirebaseGetCertPatch.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/patch/FirebaseGetCertPatch.kt deleted file mode 100644 index c7dd384d4..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/firebasegetcert/patch/FirebaseGetCertPatch.kt +++ /dev/null @@ -1,46 +0,0 @@ -package app.revanced.patches.warnwetter.misc.firebasegetcert.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patches.warnwetter.misc.firebasegetcert.annotations.FirebaseGetCertPatchCompatibility -import app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints.GetMessagingCertFingerprint -import app.revanced.patches.warnwetter.misc.firebasegetcert.fingerprints.GetReqistrationCertFingerprint - -@Name("spoof-cert-patch") -@Description("Spoofs the X-Android-Cert header.") -@FirebaseGetCertPatchCompatibility -@Version("0.0.1") -class FirebaseGetCertPatch : BytecodePatch( - listOf( - GetReqistrationCertFingerprint, - GetMessagingCertFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val spoofedInstruction = - """ - const-string v0, "0799DDF0414D3B3475E88743C91C0676793ED450" - return-object v0 - """ - - val registrationCertMethod = GetReqistrationCertFingerprint.result!!.mutableMethod - val messagingCertMethod = GetMessagingCertFingerprint.result!!.mutableMethod - - registrationCertMethod.addInstructions( - 0, - spoofedInstruction - ) - messagingCertMethod.addInstructions( - 0, - spoofedInstruction - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/annotations/PromoCodeUnlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/annotations/PromoCodeUnlockCompatibility.kt deleted file mode 100644 index f4c2cc150..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/annotations/PromoCodeUnlockCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.warnwetter.misc.promocode.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("de.dwd.warnapp")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PromoCodeUnlockCompatibility diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt deleted file mode 100644 index a0eb98d7e..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/fingerprints/PromoCodeUnlockFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.warnwetter.misc.promocode.fingerprints -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object PromoCodeUnlockFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("PromoTokenVerification;") && methodDef.name == "isValid" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/patch/PromoCodeUnlockPatch.kt b/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/patch/PromoCodeUnlockPatch.kt deleted file mode 100644 index 68ee1de05..000000000 --- a/src/main/kotlin/app/revanced/patches/warnwetter/misc/promocode/patch/PromoCodeUnlockPatch.kt +++ /dev/null @@ -1,47 +0,0 @@ -package app.revanced.patches.warnwetter.misc.promocode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.warnwetter.misc.firebasegetcert.patch.FirebaseGetCertPatch -import app.revanced.patches.warnwetter.misc.promocode.annotations.PromoCodeUnlockCompatibility -import app.revanced.patches.warnwetter.misc.promocode.fingerprints.PromoCodeUnlockFingerprint - -@DependsOn( - [ - FirebaseGetCertPatch::class - ] -) -@Patch -@Name("promo-code-unlock") -@Description("Disables the validation of promo code. Any code will work to unlock all features.") -@PromoCodeUnlockCompatibility -@Version("0.0.1") -class PromoCodeUnlockPatch : BytecodePatch( - listOf( - PromoCodeUnlockFingerprint - ) -) { - - override fun execute(context: BytecodeContext): PatchResult { - val method = PromoCodeUnlockFingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/4 v0, 0x1 - return v0 - """ - ) - - return PatchResultSuccess() - } - - -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/annotations/UnlockProCompatibility.kt b/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/annotations/UnlockProCompatibility.kt deleted file mode 100644 index b4b99e43f..000000000 --- a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/annotations/UnlockProCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.windyapp.misc.pro.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("co.windyapp.android")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class UnlockProCompatibility diff --git a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt b/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt deleted file mode 100644 index 230f83a1e..000000000 --- a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/fingerprints/CheckProFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.windyapp.misc.pro.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object CheckProFingerprint : MethodFingerprint( - "I", - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("RawUserData;") && methodDef.name == "isPro" - } -) diff --git a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/patch/UnlockProPatch.kt b/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/patch/UnlockProPatch.kt deleted file mode 100644 index fac915b59..000000000 --- a/src/main/kotlin/app/revanced/patches/windyapp/misc/unlockpro/patch/UnlockProPatch.kt +++ /dev/null @@ -1,38 +0,0 @@ -package app.revanced.patches.windyapp.misc.pro.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.windyapp.misc.pro.annotations.UnlockProCompatibility -import app.revanced.patches.windyapp.misc.pro.fingerprints.CheckProFingerprint - -@Patch -@Name("unlock-pro") -@Description("Unlocks all pro features.") -@UnlockProCompatibility -@Version("0.0.1") -class UnlockProPatch : BytecodePatch( - listOf( - CheckProFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val method = CheckProFingerprint.result!!.mutableMethod - method.addInstructions( - 0, - """ - const/16 v0, 0x1 - return v0 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt deleted file mode 100644 index c5ec9b438..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/annotation/GeneralAdsCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.youtube.ad.general.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class GeneralAdsCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/fingerprints/ReelConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/fingerprints/ReelConstructorFingerprint.kt deleted file mode 100644 index b6140dcc3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/fingerprints/ReelConstructorFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.ad.general.bytecode.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object ReelConstructorFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.INVOKE_VIRTUAL - ), - customFingerprint = { method -> - method.implementation?.instructions?.any { - it.opcode == Opcode.CONST && (it as WideLiteralInstruction).wideLiteral == GeneralAdsResourcePatch.reelMultipleItemShelfId - } ?: false - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralAdsPatch.kt deleted file mode 100644 index 219e02a70..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/bytecode/patch/GeneralAdsPatch.kt +++ /dev/null @@ -1,91 +0,0 @@ -package app.revanced.patches.youtube.ad.general.bytecode.patch - -import app.revanced.extensions.findMutableMethodOf -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility -import app.revanced.patches.youtube.ad.general.bytecode.fingerprints.ReelConstructorFingerprint -import app.revanced.patches.youtube.ad.general.resource.patch.GeneralAdsResourcePatch -import app.revanced.patches.youtube.misc.fix.verticalscroll.patch.VerticalScrollPatch -import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction -import org.jf.dexlib2.iface.instruction.formats.Instruction31i -import org.jf.dexlib2.iface.instruction.formats.Instruction35c - - -@Patch -@DependsOn([GeneralAdsResourcePatch::class, VerticalScrollPatch::class]) -@Name("general-ads") -@Description("Removes general ads.") -@GeneralAdsCompatibility -@Version("0.0.1") -class GeneralAdsPatch : BytecodePatch( - listOf(ReelConstructorFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - fun String.buildHideCall(viewRegister: Int) = "invoke-static { v$viewRegister }, " + - "Lapp/revanced/integrations/patches/GeneralAdsPatch;" + - "->" + - "$this(Landroid/view/View;)V" - - fun MutableMethod.injectHideCall(insertIndex: Int, viewRegister: Int, method: String) = - this.addInstruction(insertIndex, method.buildHideCall(viewRegister)) - - context.classes.forEach { classDef -> - classDef.methods.forEach { method -> - with(method.implementation) { - this?.instructions?.forEachIndexed { index, instruction -> - if (instruction.opcode != org.jf.dexlib2.Opcode.CONST) - return@forEachIndexed - // Instruction to store the id adAttribution into a register - if ((instruction as Instruction31i).wideLiteral != GeneralAdsResourcePatch.adAttributionId) - return@forEachIndexed - - val insertIndex = index + 1 - - // Call to get the view with the id adAttribution - with(instructions.elementAt(insertIndex)) { - if (opcode != org.jf.dexlib2.Opcode.INVOKE_VIRTUAL) - return@forEachIndexed - - // Hide the view - val viewRegister = (this as Instruction35c).registerC - context.proxy(classDef) - .mutableClass - .findMutableMethodOf(method) - .injectHideCall(insertIndex, viewRegister, "hideAdAttributionView") - } - } - } - } - } - - with( - ReelConstructorFingerprint.result - ?: return PatchResultError("Could not resolve fingerprint") - ) { - // iput-object v$viewRegister, ... - val insertIndex = this.scanResult.patternScanResult!!.startIndex + 2 - - with(this.mutableMethod) { - val viewRegister = (instruction(insertIndex) as TwoRegisterInstruction).registerA - - injectHideCall(insertIndex, viewRegister, "hideReelView") - } - - } - - return PatchResultSuccess() - } - -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt deleted file mode 100644 index af5afeafb..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/general/resource/patch/GeneralAdsResourcePatch.kt +++ /dev/null @@ -1,232 +0,0 @@ -package app.revanced.patches.youtube.ad.general.resource.patch - -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.shared.settings.preference.impl.TextPreference -import app.revanced.patches.youtube.ad.general.annotation.GeneralAdsCompatibility -import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch -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.bytecode.patch.SettingsPatch.PreferenceScreen - -@DependsOn(dependencies = [ - FixLocaleConfigErrorPatch::class, - LithoFilterPatch::class, - SettingsPatch::class, - ResourceMappingPatch::class -]) -@GeneralAdsCompatibility -@Version("0.0.1") -class GeneralAdsResourcePatch : ResourcePatch { - internal companion object { - var adAttributionId: Long = -1 - var reelMultipleItemShelfId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - PreferenceScreen.ADS.addPreferences( - SwitchPreference( - "revanced_adremover_ad_removal", - StringResource("revanced_adremover_ad_removal_enabled_title", "Hide general ads"), - true, - StringResource("revanced_adremover_ad_removal_enabled_summary_on", "General ads are hidden"), - StringResource("revanced_adremover_ad_removal_enabled_summary_off", "General ads are shown") - ), - SwitchPreference( - "revanced_adremover_buttoned", - StringResource("revanced_adremover_buttoned_enabled_title", "Hide buttoned ad"), - true, - StringResource("revanced_adremover_buttoned_enabled_summary_on", "Buttoned ads are hidden"), - StringResource("revanced_adremover_buttoned_enabled_summary_off", "Buttoned ads are shown") - ), - SwitchPreference( - "revanced_adremover_merchandise", - StringResource("revanced_adremover_merchandise_enabled_title", "Hide merchandise banners"), - true, - StringResource("revanced_adremover_merchandise_enabled_summary_on", "Merchandise banners are hidden"), - StringResource("revanced_adremover_merchandise_enabled_summary_off", "Merchandise banners are shown") - ), - SwitchPreference( - "revanced_adremover_community_posts_removal", - StringResource("revanced_adremover_community_posts_enabled_title", "Hide community posts"), - false, - StringResource("revanced_adremover_community_posts_enabled_summary_on", "Community posts are hidden"), - StringResource("revanced_adremover_community_posts_enabled_summary_off", "Community posts are shown") - ), - SwitchPreference( - "revanced_adremover_compact_banner_removal", - StringResource("revanced_adremover_compact_banner_enabled_title", "Hide compact banners"), - true, - StringResource("revanced_adremover_compact_banner_enabled_summary_on", "Compact banners are hidden"), - StringResource("revanced_adremover_compact_banner_enabled_summary_off", "Compact banners are shown") - ), - SwitchPreference( - "revanced_adremover_movie", - StringResource("revanced_adremover_movie_enabled_title", "Hide movies section"), - true, - StringResource("revanced_adremover_movie_enabled_summary_on", "Movies section is hidden"), - StringResource("revanced_adremover_movie_enabled_summary_off", "Movies section is shown") - ), - SwitchPreference( - "revanced_adremover_feed_survey", - StringResource("revanced_adremover_feed_survey_enabled_title", "Hide feed surveys"), - true, - StringResource("revanced_adremover_feed_survey_enabled_summary_on", "Feed surveys are hidden"), - StringResource("revanced_adremover_feed_survey_enabled_summary_off", "Feed surveys are shown") - ), - SwitchPreference( - "revanced_adremover_shorts", - StringResource("revanced_adremover_shorts_enabled_title", "Hide shorts"), - true, - StringResource("revanced_adremover_shorts_enabled_summary_on", "Shorts are hidden"), - StringResource("revanced_adremover_shorts_enabled_summary_off", "Shorts are shown") - ), - SwitchPreference( - "revanced_adremover_community_guidelines", - StringResource("revanced_adremover_community_guidelines_enabled_title", "Hide community guidelines"), - true, - StringResource( - "revanced_adremover_community_guidelines_enabled_summary_on", - "Community guidelines are hidden" - ), - StringResource( - "revanced_adremover_community_guidelines_enabled_summary_off", - "Community guidelines are shown" - ) - ), - SwitchPreference( - "revanced_adremover_emergency_box_removal", - StringResource("revanced_adremover_emergency_box_enabled_title", "Hide emergency boxes"), - true, - StringResource("revanced_adremover_emergency_box_enabled_summary_on", "Emergency boxes are hidden"), - StringResource("revanced_adremover_emergency_box_enabled_summary_off", "Emergency boxes are shown") - ), - SwitchPreference( - "revanced_adremover_info_panel", - StringResource("revanced_adremover_info_panel_enabled_title", "Hide info panels"), - true, - StringResource("revanced_adremover_info_panel_enabled_summary_on", "Info panels are hidden"), - StringResource("revanced_adremover_info_panel_enabled_summary_off", "Info panels are shown") - ), - SwitchPreference( - "revanced_adremover_medical_panel", - StringResource("revanced_adremover_medical_panel_enabled_title", "Hide medical panels"), - true, - StringResource("revanced_adremover_medical_panel_enabled_summary_on", "Medical panels are hidden"), - StringResource("revanced_adremover_medical_panel_enabled_summary_off", "Medical panels are shown") - ), - SwitchPreference( - "revanced_adremover_paid_content", - StringResource("revanced_adremover_paid_content_enabled_title", "Hide paid content"), - true, - StringResource("revanced_adremover_paid_content_enabled_summary_on", "Paid content is hidden"), - StringResource("revanced_adremover_paid_content_enabled_summary_off", "Paid content is shown") - ), - SwitchPreference( - "revanced_adremover_hide_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" - ) - ), - SwitchPreference( - "revanced_adremover_self_sponsor", - StringResource("revanced_adremover_self_sponsor_enabled_title", "Hide self sponsored cards"), - true, - StringResource("revanced_adremover_self_sponsor_enabled_summary_on", "Self sponsored cards are hidden"), - StringResource("revanced_adremover_self_sponsor_enabled_summary_off", "Self sponsored cards are shown") - ), - SwitchPreference( - "revanced_adremover_separator", - StringResource("revanced_adremover_separator_title", "Hide gray separator"), - true, - StringResource("revanced_adremover_separator_summary_on", "Gray separators are hidden"), - StringResource("revanced_adremover_separator_summary_off", "Gray separators are shown") - ), - SwitchPreference( - "revanced_adremover_chapter_teaser", - StringResource( - "revanced_adremover_chapter_teaser_enabled_title", - "Hide chapter teaser under videos" - ), - true, - StringResource( - "revanced_adremover_chapter_teaser_enabled_summary_on", - "Chapter teasers are hidden" - ), - StringResource( - "revanced_adremover_chapter_teaser_enabled_summary_off", - "Chapter teasers are shown" - ) - ), - app.revanced.patches.shared.settings.preference.impl.PreferenceScreen( - "revanced_adremover_custom", - StringResource("revanced_adremover_custom_title", "Custom filter"), - listOf( - SwitchPreference( - "revanced_adremover_custom_enabled", - StringResource( - "revanced_adremover_custom_enabled_title", - "Enable custom filter" - ), - false, - StringResource( - "revanced_adremover_custom_enabled_summary_on", - "Custom filter is enabled" - ), - StringResource( - "revanced_adremover_custom_enabled_summary_off", - "Custom filter is disabled" - ) - ), - // TODO: This should be a ListPreference, which does not exist yet - TextPreference( - "revanced_adremover_custom_strings", - StringResource("revanced_adremover_custom_strings_title", "Custom filter"), - InputType.STRING, - "", - StringResource( - "revanced_adremover_custom_strings_summary", - "Filter components by their name separated by a comma" - ) - ) - ) - ) - ) - - fun String.getId() = ResourceMappingPatch.resourceMappings.single { it.name == this }.id - - adAttributionId = "ad_attribution".getId() - reelMultipleItemShelfId = "reel_multiple_items_shelf".getId() - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/fingerprints/LoadVideoAdsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/fingerprints/LoadVideoAdsFingerprint.kt deleted file mode 100644 index b5a4c70e9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/fingerprints/LoadVideoAdsFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.youtube.ad.video.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object LoadVideoAdsFingerprint : MethodFingerprint( - strings = listOf( - "TriggerBundle doesn't have the required metadata specified by the trigger ", - "Tried to enter slot with no assigned slotAdapter", - "Trying to enter a slot when a slot of same type and physical position is already active. Its status: ", - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt deleted file mode 100644 index 5e16901c1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/patch/VideoAdsPatch.kt +++ /dev/null @@ -1,58 +0,0 @@ -package app.revanced.patches.youtube.ad.video.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.ad.video.annotations.VideoAdsCompatibility -import app.revanced.patches.youtube.ad.video.fingerprints.LoadVideoAdsFingerprint -import app.revanced.patches.youtube.misc.fix.playback.patch.FixPlaybackPatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class, FixPlaybackPatch::class]) -@Name("video-ads") -@Description("Removes ads in the video player.") -@VideoAdsCompatibility -@Version("0.0.1") -class VideoAdsPatch : BytecodePatch( - listOf( - LoadVideoAdsFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.ADS.addPreferences( - SwitchPreference( - "revanced_video_ads_removal", - StringResource("revanced_video_ads_removal_title", "Hide video ads"), - true, - StringResource("revanced_video_ads_removal_summary_on", "Video ads are hidden"), - StringResource("revanced_video_ads_removal_summary_off", "Video ads are shown") - ) - ) - - val loadVideoAdsFingerprintMethod = LoadVideoAdsFingerprint.result!!.mutableMethod - - loadVideoAdsFingerprintMethod.addInstructions( - 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/VideoAdsPatch;->shouldShowAds()Z - move-result v0 - if-nez v0, :show_video_ads - return-void - """, listOf(ExternalLabel("show_video_ads", loadVideoAdsFingerprintMethod.instruction(0))) - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/fingerprints/ComponentContextParserFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/fingerprints/ComponentContextParserFingerprint.kt index 7f661ac49..13225beb7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/ComponentContextParserFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/fingerprints/ComponentContextParserFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.litho.filter.fingerprints +package app.revanced.patches.youtube.ads.general.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/fingerprints/EmptyComponentBuilderFingerprint.kt similarity index 76% rename from src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/fingerprints/EmptyComponentBuilderFingerprint.kt index 1842275a5..0ac4f30d7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/EmptyComponentBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/fingerprints/EmptyComponentBuilderFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.litho.filter.fingerprints +package app.revanced.patches.youtube.ads.general.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/patch/GeneralAdsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/patch/GeneralAdsBytecodePatch.kt new file mode 100644 index 000000000..11e18b45a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/patch/GeneralAdsBytecodePatch.kt @@ -0,0 +1,99 @@ +package app.revanced.patches.youtube.ads.general.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableClass +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.ads.general.bytecode.fingerprints.ComponentContextParserFingerprint +import app.revanced.patches.youtube.ads.general.bytecode.fingerprints.EmptyComponentBuilderFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.util.bytecode.BytecodeHelper +import app.revanced.shared.util.integrations.Constants.ADS_PATH +import org.jf.dexlib2.builder.instruction.BuilderInstruction21s +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.Opcode + +@DependsOn([ResourceMappingPatch::class]) +@Name("hide-general-ads-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class GeneralAdsBytecodePatch : BytecodePatch( + listOf(ComponentContextParserFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + ComponentContextParserFingerprint.result?.let { result -> + val builderMethodIndex = EmptyComponentBuilderFingerprint + .also { it.resolve(context, result.mutableMethod, result.mutableClass) } + .let { it.result!!.scanResult.patternScanResult!!.startIndex } + + val emptyComponentFieldIndex = builderMethodIndex + 2 + + with(result.mutableMethod) { + val insertHookIndex = implementation!!.instructions.indexOfFirst { + it.opcode == Opcode.CONST_16 && + (it as BuilderInstruction21s).narrowLiteral == 124 + } + 3 + + val stringBuilderRegister = (instruction(insertHookIndex) as OneRegisterInstruction).registerA + val clobberedRegister = (instruction(insertHookIndex - 3) as OneRegisterInstruction).registerA + + val bufferIndex = implementation!!.instructions.indexOfFirst { + it.opcode == Opcode.CONST && + (it as Instruction31i).narrowLiteral == 183314536 + } - 1 + + val bufferRegister = (instruction(bufferIndex) as OneRegisterInstruction).registerA + + val builderMethodDescriptor = instruction(builderMethodIndex).toDescriptor() + val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).toDescriptor() + + addInstructions( + insertHookIndex, // right after setting the component.pathBuilder field, + """ + invoke-static {v$stringBuilderRegister, v$bufferRegister}, $ADS_PATH/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z + move-result v$clobberedRegister + if-eqz v$clobberedRegister, :not_an_ad + move-object/from16 v$bufferRegister, p1 + invoke-static {v$bufferRegister}, $builderMethodDescriptor + move-result-object v0 + iget-object v0, v0, $emptyComponentFieldDescriptor + return-object v0 + """, + listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex))) + ) + } + } ?: return PatchResultError("Could not find the method to hook.") + + BytecodeHelper.patchStatus(context, "GeneralAds") + + return PatchResultSuccess() + } + + private companion object { + fun Instruction.toDescriptor() = when (val reference = (this as? ReferenceInstruction)?.reference) { + is MethodReference -> "${reference.definingClass}->${reference.name}(${ + reference.parameterTypes.joinToString( + "" + ) { it } + })${reference.returnType}" + is FieldReference -> "${reference.definingClass}->${reference.name}:${reference.type}" + else -> throw PatchResultError("Unsupported reference type") + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/patch/GeneralAdsSecondaryBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/patch/GeneralAdsSecondaryBytecodePatch.kt new file mode 100644 index 000000000..872571e56 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/general/bytecode/patch/GeneralAdsSecondaryBytecodePatch.kt @@ -0,0 +1,80 @@ +package app.revanced.patches.youtube.ads.general.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.* +import org.jf.dexlib2.Opcode + +@Name("hide-general-ads-secondary-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class GeneralAdsSecondaryBytecodePatch : BytecodePatch() { + private val resourceIds = arrayOf( + "ad_attribution", + "horizontal_card_list", + "album_card" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // general ads + val insertIndex = index + 1 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.INVOKE_VIRTUAL) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (invokeInstruction as Instruction35c).registerC + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAdAttributionView") + } + + resourceIds[1] -> { // breaking news + val insertIndex = index + 4 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (invokeInstruction as Instruction21c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideBreakingNewsShelf") + } + + resourceIds[2] -> { // album cards + val insertIndex = index + 4 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (invokeInstruction as Instruction21c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "ads/GeneralAdsPatch", "hideAlbumCards") + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ads/general/resource/patch/GeneralAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/general/resource/patch/GeneralAdsPatch.kt new file mode 100644 index 000000000..63c36a26c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/general/resource/patch/GeneralAdsPatch.kt @@ -0,0 +1,85 @@ +package app.revanced.patches.youtube.ads.general.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch +import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsSecondaryBytecodePatch +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.doRecursively +import app.revanced.shared.extensions.startsWithAny +import app.revanced.shared.util.resources.ResourceHelper +import org.w3c.dom.Element + +@Patch +@Name("hide-general-ads") +@Description("Hooks the method which parses the bytes into a ComponentContext to filter components.") +@DependsOn( + [ + GeneralAdsBytecodePatch::class, + GeneralAdsSecondaryBytecodePatch::class, + LithoFilterPatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class GeneralAdsPatch : ResourcePatch { + private val resourceFileNames = arrayOf( + "promoted_", + "promotion_", + "compact_premium_", + "compact_promoted_", + ) + + private val replacements = arrayOf( + "height", + "width", + "marginTop" + ) + + override fun execute(context: ResourceContext): PatchResult { + context.forEach { + + if (!it.name.startsWithAny(*resourceFileNames)) return@forEach + + // for each file in the "layouts" directory replace all necessary attributes content + context.xmlEditor[it.absolutePath].use { editor -> + editor.file.doRecursively { node -> + replacements.forEach replacement@{ replacement -> + if (node !is Element) return@replacement + + node.getAttributeNode("android:layout_$replacement")?.let { attribute -> + attribute.textContent = "0.0dip" + } + } + } + } + } + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: ADS_SETTINGS", + "SETTINGS: HIDE_GENERAL_ADS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-general-ads" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ads/video/bytecode/patch/VideoAdsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/video/bytecode/patch/VideoAdsBytecodePatch.kt new file mode 100644 index 000000000..dface2daa --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/video/bytecode/patch/VideoAdsBytecodePatch.kt @@ -0,0 +1,37 @@ +package app.revanced.patches.youtube.ads.video.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.videoads.GeneralVideoAdsPatch +import app.revanced.shared.util.bytecode.BytecodeHelper +import app.revanced.shared.util.integrations.Constants.ADS_PATH + +@DependsOn( + [ + GeneralVideoAdsPatch::class, + MainstreamVideoIdPatch::class + ] +) +@Name("hide-video-ads-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class VideoAdsBytecodePatch : BytecodePatch() { + override fun execute(context: BytecodeContext): PatchResult { + val INTEGRATIONS_CLASS_DESCRIPTOR = "$ADS_PATH/HideVideoAdsPatch;->hideVideoAds()Z" + + GeneralVideoAdsPatch.injectLegacyAds(INTEGRATIONS_CLASS_DESCRIPTOR) + + GeneralVideoAdsPatch.injectMainstreamAds(INTEGRATIONS_CLASS_DESCRIPTOR) + + BytecodeHelper.patchStatus(context, "VideoAds") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/ads/video/resource/patch/VideoAdsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/ads/video/resource/patch/VideoAdsPatch.kt new file mode 100644 index 000000000..699a1c4bc --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/ads/video/resource/patch/VideoAdsPatch.kt @@ -0,0 +1,56 @@ +package app.revanced.patches.youtube.ads.video.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.ads.video.bytecode.patch.VideoAdsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-video-ads") +@Description("Removes ads in the video player.") +@DependsOn( + [ + VideoAdsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class VideoAdsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: ADS_SETTINGS", + "SETTINGS: HIDE_VIDEO_ADS" + ) + + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: EXTENDED_SETTINGS", + "SETTINGS: EXPERIMENTAL_FLAGS", + "SETTINGS: FIX_VIDEO_PLAYBACK" + ) + + ResourceHelper.patchSuccess( + context, + "hide-video-ads" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutoNavInformerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoNavInformerFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutoNavInformerFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoNavInformerFingerprint.kt index 469d5640d..d2cdbcadb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/AutoNavInformerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoNavInformerFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.autoplaybutton.fingerprints +package app.revanced.patches.youtube.button.autorepeat.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoRepeatFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoRepeatFingerprint.kt index a16683b14..105932384 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoRepeatFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.autorepeat.fingerprints +package app.revanced.patches.youtube.button.autorepeat.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoRepeatParentFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoRepeatParentFingerprint.kt index 81d6b0083..80f230031 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/fingerprints/AutoRepeatParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/fingerprints/AutoRepeatParentFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.autorepeat.fingerprints +package app.revanced.patches.youtube.button.autorepeat.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/patch/AutoRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/patch/AutoRepeatPatch.kt new file mode 100644 index 000000000..ee5f2aec0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/autorepeat/patch/AutoRepeatPatch.kt @@ -0,0 +1,57 @@ +package app.revanced.patches.youtube.button.autorepeat.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.button.autorepeat.fingerprints.AutoNavInformerFingerprint +import app.revanced.patches.youtube.button.autorepeat.fingerprints.AutoRepeatFingerprint +import app.revanced.patches.youtube.button.autorepeat.fingerprints.AutoRepeatParentFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.UTILS_PATH +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH + +@Name("always-autorepeat") +@YouTubeCompatibility +@Version("0.0.1") +class AutoRepeatPatch : BytecodePatch( + listOf( + AutoRepeatParentFingerprint, + AutoNavInformerFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + with(AutoRepeatFingerprint.also { + it.resolve(context, AutoRepeatParentFingerprint.result!!.classDef) + }.result!!.mutableMethod) { + addInstructions( + 0, """ + invoke-static {}, $VIDEO_PATH/VideoInformation;->videoEnded()Z + move-result v0 + if-eqz v0, :noautorepeat + return-void + """, listOf(ExternalLabel("noautorepeat", instruction(0))) + ) + } + + with(AutoNavInformerFingerprint.result!!.mutableMethod) { + addInstructions( + 0, """ + invoke-static {}, $UTILS_PATH/EnableAutoRepeatPatch;->enableAutoRepeat()Z + move-result v0 + if-eqz v0, :hidden + const/4 v0, 0x0 + return v0 + """, listOf(ExternalLabel("hidden", instruction(0))) + ) + } + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/overlaybuttons/bytecode/patch/OverlayButtonsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/button/overlaybuttons/bytecode/patch/OverlayButtonsBytecodePatch.kt new file mode 100644 index 000000000..7ddd29751 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/overlaybuttons/bytecode/patch/OverlayButtonsBytecodePatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.youtube.button.overlaybuttons.bytecode.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch +import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.BUTTON_PATH + +@Name("overlay-buttons-bytecode-patch") +@DependsOn( + dependencies = [ + PlayerControlsBytecodePatch::class, + MainstreamVideoIdPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class OverlayButtonsBytecodePatch : BytecodePatch() { + override fun execute(context: BytecodeContext): PatchResult { + val AutoRepeat = "$BUTTON_PATH/AutoRepeat;" + val Copy = "$BUTTON_PATH/Copy;" + val CopyWithTimeStamp = "$BUTTON_PATH/CopyWithTimeStamp;" + val Download = "$BUTTON_PATH/Download;" + val Whitelists = "$BUTTON_PATH/Whitelists;" + + arrayOf( + Download, + AutoRepeat, + CopyWithTimeStamp, + Copy, + Whitelists + ).forEach { descriptor -> + PlayerControlsBytecodePatch.initializeControl(descriptor) + PlayerControlsBytecodePatch.injectVisibility(descriptor) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/overlaybuttons/resource/patch/OverlayButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/button/overlaybuttons/resource/patch/OverlayButtonsPatch.kt new file mode 100644 index 000000000..8e7140954 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/overlaybuttons/resource/patch/OverlayButtonsPatch.kt @@ -0,0 +1,122 @@ +package app.revanced.patches.youtube.button.overlaybuttons.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.button.overlaybuttons.bytecode.patch.OverlayButtonsBytecodePatch +import app.revanced.patches.youtube.button.autorepeat.patch.AutoRepeatPatch +import app.revanced.patches.youtube.button.whitelist.patch.WhitelistPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode + +@Patch +@Name("overlay-buttons") +@Description("Add overlay buttons for ReVanced Extended.") +@DependsOn( + [ + AutoRepeatPatch::class, + OverlayButtonsBytecodePatch::class, + PatchOptions::class, + SettingsPatch::class, + WhitelistPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class OverlayButtonsResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + var icon = PatchOptions.Overlay_Buttons_Icon + + /* + * Copy resources + */ + arrayOf( + ResourceUtils.ResourceGroup( + "drawable", + "playlist_repeat_button.xml", + "playlist_shuffle_button.xml", + "revanced_repeat_icon.xml" + ) + ).forEach { resourceGroup -> + context.copyResources("youtube/overlaybuttons", resourceGroup) + } + + arrayOf( + ResourceUtils.ResourceGroup( + "drawable-xxhdpi", + "ic_fullscreen_vertical_button.png", + "ic_vr.png", + "quantum_ic_fullscreen_exit_grey600_24.png", + "quantum_ic_fullscreen_exit_white_24.png", + "quantum_ic_fullscreen_grey600_24.png", + "quantum_ic_fullscreen_white_24.png", + "revanced_copy_icon.png", + "revanced_copy_icon_with_time.png", + "revanced_download_icon.png", + "revanced_whitelist_icon.png", + "yt_outline_arrow_repeat_1_white_24.png", + "yt_outline_arrow_shuffle_1_white_24.png", + "yt_outline_screen_full_exit_white_24.png", + "yt_outline_screen_full_white_24.png" + ) + ).forEach { resourceGroup -> + context.copyResources("youtube/overlaybuttons/$icon", resourceGroup) + } + + /* + * Copy preference fragments + */ + + context.copyXmlNode("youtube/overlaybuttons/host", "layout/youtube_controls_bottom_ui_container.xml", "android.support.constraint.ConstraintLayout") + + val container = context["res/layout/youtube_controls_bottom_ui_container.xml"] + container.writeText( + container.readText() + .replace( + "yt:layout_constraintRight_toLeftOf=\"@id/fullscreen_button", + "yt:layout_constraintRight_toLeftOf=\"@+id/whitelist_button" + ).replace( + "60", + "48" + ).replace( + "paddingBottom=\"16", + "paddingBottom=\"28" + ).replace( + "paddingLeft=\"12", + "paddingLeft=\"0" + ).replace( + "paddingRight=\"12", + "paddingRight=\"0" + ) + ) + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: OVERLAY_BUTTONS", + "SETTINGS: OVERLAY_BUTTONS" + ) + + ResourceHelper.patchSuccess( + context, + "overlay-buttons" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PlayerResponseModelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PlayerResponseModelFingerprint.kt new file mode 100644 index 000000000..e1915c07b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PlayerResponseModelFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.button.whitelist.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object PlayerResponseModelFingerprint : MethodFingerprint( + returnType = "Z", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("J", "L"), + strings = listOf( + "Attempting to seek during an ad", + "currentPositionMs.", + ) +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PlayerResponseModelParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PlayerResponseModelParentFingerprint.kt new file mode 100644 index 000000000..653390fea --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PlayerResponseModelParentFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.button.whitelist.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object PlayerResponseModelParentFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), + strings = listOf( + "setMetadata may only be called once", + "Person", + ) +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PrimaryInjectFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PrimaryInjectFingerprint.kt new file mode 100644 index 000000000..4c03b23c8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/PrimaryInjectFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.youtube.button.whitelist.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object PrimaryInjectFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf(), + opcodes = listOf( + Opcode.IF_NEZ, + Opcode.CONST_STRING, + Opcode.INVOKE_STATIC, + Opcode.RETURN_VOID, + Opcode.IGET_OBJECT + ), + strings = listOf( + "play() called when the player wasn\'t loaded.", + ) +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/SecondaryInjectFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/SecondaryInjectFingerprint.kt new file mode 100644 index 000000000..da53b8a8a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/fingerprint/SecondaryInjectFingerprint.kt @@ -0,0 +1,26 @@ +package app.revanced.patches.youtube.button.whitelist.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object SecondaryInjectFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.GOTO, + Opcode.IPUT_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT + ) +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/patch/WhitelistPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/patch/WhitelistPatch.kt new file mode 100644 index 000000000..e6a864f53 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/button/whitelist/patch/WhitelistPatch.kt @@ -0,0 +1,109 @@ +package app.revanced.patches.youtube.button.whitelist.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.extensions.or +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patcher.util.smali.toInstructions +import app.revanced.patches.youtube.button.whitelist.fingerprint.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.builder.instruction.BuilderInstruction21c +import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodImplementation +import org.jf.dexlib2.Opcode + +@Name("channel-whitelist") +@YouTubeCompatibility +@Version("0.0.1") +class WhitelistPatch : BytecodePatch( + listOf( + PlayerResponseModelFingerprint, + PlayerResponseModelParentFingerprint, + PrimaryInjectFingerprint, + SecondaryInjectFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val PlayerResponseModelParentResult = PlayerResponseModelParentFingerprint.result!! + val PlayerResponseModelParentInstructions = PlayerResponseModelParentResult.mutableMethod.implementation!!.instructions + + val injectIndex = PlayerResponseModelParentInstructions.indexOfFirst { + it.opcode == Opcode.CONST_STRING && + (it as BuilderInstruction21c).reference.toString() == "Person" + } + 2 + + val PlayerResponseModelReference = + PlayerResponseModelParentResult.method.let { method -> + (method.implementation!!.instructions.elementAt(injectIndex) as ReferenceInstruction).reference as DexBackedMethodReference + } + + val PlayerResponseModelResult = PlayerResponseModelFingerprint.result!! + + val PrimaryReference = + PlayerResponseModelResult.method.let { method -> + (method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as FieldReference + } + val SecondaryReference = + PlayerResponseModelResult.method.let { method -> + (method.implementation!!.instructions.elementAt(3) as ReferenceInstruction).reference as FieldReference + } + val TertiaryReference = + PlayerResponseModelResult.method.let { method -> + (method.implementation!!.instructions.elementAt(4) as ReferenceInstruction).reference as MethodReference + } + + val classDef = PlayerResponseModelResult.mutableClass + classDef.methods.add( + ImmutableMethod( + classDef.type, + "setCurrentVideoInformation", + listOf(), + "V", + AccessFlags.PRIVATE or AccessFlags.FINAL, + null, + null, + ImmutableMethodImplementation( + 2, """ + iget-object v0, v1, ${PlayerResponseModelResult.classDef.type}->${PrimaryReference.name}:${PrimaryReference.type} + iget-object v0, v0, ${PrimaryReference.type}->${SecondaryReference.name}:${SecondaryReference.type} + invoke-interface {v0}, $TertiaryReference + move-result-object v0 + invoke-interface {v0}, $PlayerResponseModelReference + move-result-object v0 + invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V + return-void + """.toInstructions(), null, null + ) + ).toMutable() + ) + + + listOf( + PrimaryInjectFingerprint, + SecondaryInjectFingerprint + ).forEach { fingerprint -> + val result = fingerprint.result ?: return PatchResultError("${fingerprint.name} not found") + val method = result.mutableMethod + val index = result.scanResult.patternScanResult!!.endIndex + 1 + method.addInstruction( + index, + "invoke-direct {p0}, ${PlayerResponseModelResult.classDef.type}->setCurrentVideoInformation()V" + ) + } + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/bytecode/fingerprints/LayoutSwitchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/bytecode/fingerprints/LayoutSwitchFingerprint.kt new file mode 100644 index 000000000..13e3cc57c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/bytecode/fingerprints/LayoutSwitchFingerprint.kt @@ -0,0 +1,32 @@ +package app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object LayoutSwitchFingerprint : MethodFingerprint( + "I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT, + Opcode.IF_NEZ, + Opcode.CONST_4, + Opcode.RETURN, + Opcode.CONST_16, + Opcode.IF_GE, + Opcode.CONST_4, + Opcode.RETURN, + Opcode.CONST_16, + Opcode.IF_GE, + Opcode.CONST_4, + Opcode.RETURN, + Opcode.CONST_16, + Opcode.IF_GE, + Opcode.CONST_4, + Opcode.RETURN, + Opcode.CONST_4, + Opcode.RETURN + ) +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/bytecode/patch/LayoutSwitchBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/bytecode/patch/LayoutSwitchBytecodePatch.kt new file mode 100644 index 000000000..ebd92c4d4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/bytecode/patch/LayoutSwitchBytecodePatch.kt @@ -0,0 +1,33 @@ +package app.revanced.patches.youtube.extended.layoutswitch.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints.LayoutSwitchFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH + +@Name("layout-switch-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class LayoutSwitchBytecodePatch : BytecodePatch( + listOf( + LayoutSwitchFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + LayoutSwitchFingerprint.result!!.mutableMethod.addInstructions( + 4, """ + invoke-static {p0}, $EXTENDED_PATH/LayoutOverridePatch;->getLayoutOverride(I)I + move-result p0 + """ + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/resource/patch/LayoutSwitchPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/resource/patch/LayoutSwitchPatch.kt new file mode 100644 index 000000000..4624ad026 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/extended/layoutswitch/resource/patch/LayoutSwitchPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.extended.layoutswitch.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.extended.layoutswitch.bytecode.patch.LayoutSwitchBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("layout-switch") +@Description("Tricks the dpi to use some tablet/phone layouts.") +@DependsOn( + [ + LayoutSwitchBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class LayoutSwitchPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: EXTENDED_SETTINGS", + "SETTINGS: EXPERIMENTAL_FLAGS", + "SETTINGS: LAYOUT_SWITCH" + ) + + ResourceHelper.patchSuccess( + context, + "layout-switch" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/bytecode/fingerprints/OldLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/bytecode/fingerprints/OldLayoutFingerprint.kt new file mode 100644 index 000000000..3f9a4267c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/bytecode/fingerprints/OldLayoutFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object OldLayoutFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( + Opcode.IGET_OBJECT, + Opcode.GOTO, + Opcode.CONST_STRING, + ), + strings = listOf("Unset") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/bytecode/patch/OldLayoutBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/bytecode/patch/OldLayoutBytecodePatch.kt new file mode 100644 index 000000000..4befc09d7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/bytecode/patch/OldLayoutBytecodePatch.kt @@ -0,0 +1,42 @@ +package app.revanced.patches.youtube.extended.oldlayout.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints.OldLayoutFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH +import app.revanced.shared.util.integrations.Constants.UTILS_PATH +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("enable-old-layout-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class OldLayoutBytecodePatch : BytecodePatch( + listOf( + OldLayoutFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + val result = OldLayoutFingerprint.result!! + val method = result.mutableMethod + val index = result.scanResult.patternScanResult!!.startIndex + val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA + + method.addInstructions( + index + 1, """ + invoke-static {v$register}, $EXTENDED_PATH/VersionOverridePatch;->getVersionOverride(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$register + """ + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/resource/patch/OldLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/resource/patch/OldLayoutPatch.kt new file mode 100644 index 000000000..a6f49269c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/extended/oldlayout/resource/patch/OldLayoutPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.extended.oldlayout.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.extended.oldlayout.bytecode.patch.OldLayoutBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-old-layout") +@Description("Spoof the YouTube client version to use the old layout.") +@DependsOn( + [ + OldLayoutBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class OldLayoutPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: EXTENDED_SETTINGS", + "SETTINGS: EXPERIMENTAL_FLAGS", + "SETTINGS: ENABLE_OLD_LAYOUT" + ) + + ResourceHelper.patchSuccess( + context, + "enable-old-layout" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt deleted file mode 100644 index 3f1e33979..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/annotation/DownloadsCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.youtube.interaction.downloads.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DownloadsCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt deleted file mode 100644 index c5e6ba0cd..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/bytecode/patch/DownloadsBytecodePatch.kt +++ /dev/null @@ -1,52 +0,0 @@ -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.BytecodeContext -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.interaction.downloads.annotation.DownloadsCompatibility -import app.revanced.patches.youtube.interaction.downloads.resource.patch.DownloadsResourcePatch -import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch -import app.revanced.patches.youtube.misc.video.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(context: BytecodeContext): 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() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt deleted file mode 100644 index 0ea6834dd..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/resource/patch/DownloadsResourcePatch.kt +++ /dev/null @@ -1,72 +0,0 @@ -package app.revanced.patches.youtube.interaction.downloads.resource.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.settings.preference.impl.* -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.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources -import app.revanced.util.resources.ResourceUtils.mergeStrings - -@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(context: ResourceContext): 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 shown"), - StringResource("revanced_downloads_enabled_summary_off", "Download button is not shown") - ), - TextPreference( - "revanced_downloads_package_name", - StringResource("revanced_downloads_package_name_title", "Downloader package name"), - InputType.STRING, - "org.schabi.newpipe" /* NewPipe */, - StringResource("revanced_downloads_package_name_summary", "Package name of the downloader app such as NewPipe\\'s or PowerTube\\'s") - ) - ), - StringResource("revanced_downloads_summary", "Settings related to downloads") - ) - ) - - - /* - * Copy strings - */ - - context.mergeStrings("downloads/host/values/strings.xml") - - /* - * Copy resources - */ - - context.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() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt deleted file mode 100644 index 5f282ece5..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/annotation/SeekbarTappingCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.youtube.interaction.seekbar.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SeekbarTappingCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt deleted file mode 100644 index 6691d5d85..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/annotation/SwipeControlsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.interaction.swipecontrols.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SwipeControlsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt deleted file mode 100644 index 01cfffd5d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/resource/SwipeControlsResourcePatch.kt +++ /dev/null @@ -1,111 +0,0 @@ -package app.revanced.patches.youtube.interaction.swipecontrols.patch.resource - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.shared.settings.preference.impl.TextPreference -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.youtube.interaction.swipecontrols.annotation.SwipeControlsCompatibility -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources - -@Name("swipe-controls-resource-patch") -@DependsOn([SettingsPatch::class]) -@SwipeControlsCompatibility -@Version("0.0.1") -class SwipeControlsResourcePatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - PreferenceScreen( - "revanced_swipe_controls", StringResource("revanced_swipe_controls_title", "Swipe controls"), listOf( - 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") - ) - ) - - context.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() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt deleted file mode 100644 index fc1f4c925..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/annotations/AutoCaptionsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.autocaptions.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class AutoCaptionsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt deleted file mode 100644 index 38c12c992..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/patch/AutoCaptionsPatch.kt +++ /dev/null @@ -1,80 +0,0 @@ -package app.revanced.patches.youtube.layout.autocaptions.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.autocaptions.annotations.AutoCaptionsCompatibility -import app.revanced.patches.youtube.layout.autocaptions.fingerprints.StartVideoInformerFingerprint -import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleButtonControllerFingerprint -import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleTrackFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("disable-auto-captions") -@Description("Disable forced captions from being automatically enabled.") -@AutoCaptionsCompatibility -@Version("0.0.1") -class AutoCaptionsPatch : BytecodePatch( - listOf( - StartVideoInformerFingerprint, SubtitleButtonControllerFingerprint, SubtitleTrackFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_autocaptions_enabled", - StringResource("revanced_autocaptions_enabled_title", "Disable auto-captions"), - false, - StringResource("revanced_autocaptions_summary_on", "Auto-captions are disabled"), - StringResource("revanced_autocaptions_summary_off", "Auto-captions are enabled") - ) - ) - - val startVideoInformerMethod = StartVideoInformerFingerprint.result!!.mutableMethod - - startVideoInformerMethod.addInstructions( - 0, """ - const/4 v0, 0x0 - sput-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z - """ - ) - - val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod - - subtitleButtonControllerMethod.addInstructions( - 0, """ - const/4 v0, 0x1 - sput-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z - """ - ) - - val subtitleTrackMethod = SubtitleTrackFingerprint.result!!.mutableMethod - - subtitleTrackMethod.addInstructions( - 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->autoCaptionsEnabled()Z - move-result v0 - if-eqz v0, :auto_captions_enabled - sget-boolean v0, Lapp/revanced/integrations/patches/DisableAutoCaptionsPatch;->captionsButtonDisabled:Z - if-nez v0, :auto_captions_enabled - const/4 v0, 0x1 - return v0 - :auto_captions_enabled - nop - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/annotations/AutoplayButtonCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/annotations/AutoplayButtonCompatibility.kt deleted file mode 100644 index 0a32de472..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/annotations/AutoplayButtonCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.autoplaybutton.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class AutoplayButtonCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt deleted file mode 100644 index 079114432..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/patch/HideAutoplayButtonPatch.kt +++ /dev/null @@ -1,92 +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.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.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.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.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, ResourceMappingPatch::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(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_autoplay_button", - StringResource("revanced_hide_autoplay_button_title", "Hide autoplay button"), - true, - StringResource("revanced_hide_autoplay_button_summary_on", "Autoplay button is hidden"), - StringResource("revanced_hide_autoplay_button_summary_off", "Autoplay button is shown") - ) - ) - - 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 = ResourceMappingPatch.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() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/annotations/PremiumHeadingCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/annotations/PremiumHeadingCompatibility.kt deleted file mode 100644 index 96b1d5078..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/annotations/PremiumHeadingCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.branding.header.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PremiumHeadingCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/annotations/CustomBrandingCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/annotations/CustomBrandingCompatibility.kt deleted file mode 100644 index a0ffc713b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/annotations/CustomBrandingCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.branding.icon.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CustomBrandingCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/patch/CustomBrandingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/patch/CustomBrandingPatch.kt deleted file mode 100644 index f373fd6c0..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/icon/patch/CustomBrandingPatch.kt +++ /dev/null @@ -1,94 +0,0 @@ -package app.revanced.patches.youtube.layout.branding.icon.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.* -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.branding.icon.annotations.CustomBrandingCompatibility -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources -import java.io.File -import java.nio.file.Files - -@Patch -@DependsOn([FixLocaleConfigErrorPatch::class]) -@Name("custom-branding") -@Description("Changes the YouTube launcher icon and name to your choice (defaults to ReVanced).") -@CustomBrandingCompatibility -@Version("0.0.1") -class CustomBrandingPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - fun copyResources(resourceGroups: List) { - iconPath?.let { iconPathString -> - val iconPath = File(iconPathString) - val resourceDirectory = context["res"] - - resourceGroups.forEach { group -> - val fromDirectory = iconPath.resolve(group.resourceDirectoryName) - val toDirectory = resourceDirectory.resolve(group.resourceDirectoryName) - - group.resources.forEach { iconFileName -> - Files.write( - toDirectory.resolve(iconFileName).toPath(), - fromDirectory.resolve(iconFileName).readBytes() - ) - } - } - } ?: resourceGroups.forEach { context.copyResources("branding", it) } - } - - val iconResourceFileNames = arrayOf( - "adaptiveproduct_youtube_background_color_108", - "adaptiveproduct_youtube_foreground_color_108", - "ic_launcher", - "ic_launcher_round" - ).map { "$it.png" }.toTypedArray() - - fun createGroup(directory: String) = ResourceUtils.ResourceGroup( - directory, *iconResourceFileNames - ) - - // change the app icon - arrayOf("xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi") - .map { "mipmap-$it" } - .map(::createGroup) - .let(::copyResources) - - // change the name of the app - val manifest = context["AndroidManifest.xml"] - manifest.writeText( - manifest.readText() - .replace( - "android:label=\"@string/application_name", - "android:label=\"$appName" - ) - ) - - return PatchResultSuccess() - } - - companion object : OptionsContainer() { - private var appName: String? by option( - PatchOption.StringOption( - key = "appName", - default = "YouTube ReVanced", - title = "Application Name", - description = "The name of the application it will show on your home screen.", - required = true - ) - ) - - private var iconPath: String? by option( - PatchOption.StringOption( - key = "iconPath", - default = null, - title = "App Icon Path", - description = "A path containing mipmap resource folders with icons." - ) - ) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttomplayer/buttoncontainer/patch/ButtonContainerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttomplayer/buttoncontainer/patch/ButtonContainerPatch.kt new file mode 100644 index 000000000..7db3f23f3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttomplayer/buttoncontainer/patch/ButtonContainerPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.buttomplayer.buttoncontainer.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-button-container") +@Description("Adds options to hide action buttons under a video.") +@DependsOn( + [ + LithoFilterPatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ButtonContainerPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: BOTTOM_PLAYER", + "SETTINGS: BUTTON_CONTAINER" + ) + + ResourceHelper.patchSuccess( + context, + "hide-button-container" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttomplayer/comment/patch/CommentComponentPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttomplayer/comment/patch/CommentComponentPatch.kt new file mode 100644 index 000000000..0b5cb3088 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/buttomplayer/comment/patch/CommentComponentPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.buttomplayer.comment.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-comment-component") +@Description("Adds options to hide comment component under a video.") +@DependsOn( + [ + GeneralAdsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class CommentComponentPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: BOTTOM_PLAYER", + "SETTINGS: COMMENT_COMPONENT" + ) + + ResourceHelper.patchSuccess( + context, + "hide-comment-component" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/annotations/HideButtonsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/annotations/HideButtonsCompatibility.kt deleted file mode 100644 index c2847ffda..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/annotations/HideButtonsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.buttons.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideButtonsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/patch/HideButtonsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/patch/HideButtonsPatch.kt deleted file mode 100644 index bd82e1dda..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/buttons/patch/HideButtonsPatch.kt +++ /dev/null @@ -1,81 +0,0 @@ -package app.revanced.patches.youtube.layout.buttons.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch -import app.revanced.patches.youtube.layout.buttons.annotations.HideButtonsCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([ResourceMappingPatch::class, LithoFilterPatch::class]) -@Name("hide-video-buttons") -@Description("Adds options to hide action buttons under a video.") -@HideButtonsCompatibility -@Version("0.0.1") -class HideButtonsPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - PreferenceScreen( - "revanced_hide_buttons", - StringResource("revanced_hide_buttons_title", "Hide action buttons"), - listOf( - SwitchPreference( - "revanced_hide_like_button", - StringResource("revanced_hide_like_button_title", "Hide like button"), - false, - StringResource("revanced_hide_like_button_summary_on", "Like button is hidden"), - StringResource("revanced_hide_like_button_summary_off", "Like button is shown") - ), - SwitchPreference( - "revanced_hide_dislike_button", - StringResource("revanced_hide_dislike_button_title", "Hide dislike button"), - false, - StringResource("revanced_hide_dislike_button_summary_on", "Dislike button is hidden"), - StringResource("revanced_hide_dislike_button_summary_off", "Dislike button is shown") - ), - SwitchPreference( - "revanced_hide_download_button", - StringResource("revanced_hide_download_button_title", "Hide download button"), - false, - StringResource("revanced_hide_download_button_summary_on", "Download button is hidden"), - StringResource("revanced_hide_download_button_summary_off", "Download button is shown") - ), - SwitchPreference( - "revanced_hide_playlist_button", - StringResource("revanced_hide_playlist_button_title", "Hide playlist button"), - false, - StringResource("revanced_hide_playlist_button_summary_on", "Playlist button is hidden"), - StringResource("revanced_hide_playlist_button_summary_off", "Playlist button is shown") - ), - SwitchPreference( - "revanced_hide_action_button", - StringResource("revanced_hide_action_button_title", "Hide create, clip and thanks buttons"), - true, - StringResource("revanced_hide_action_button_summary_on", "Buttons are hidden"), - StringResource("revanced_hide_action_button_summary_off", "Buttons are shown") - ), - SwitchPreference( - "revanced_hide_share_button", - StringResource("revanced_hide_share_button_title", "Hide share button"), - false, - StringResource("revanced_hide_share_button_summary_on", "Share button is hidden"), - StringResource("revanced_hide_share_button_summaryoff", "Share button is shown") - ), - ), - StringResource("revanced_hide_buttons_summary", "Hide or show buttons under videos") - ) - ) - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/annotations/CastPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/annotations/CastPatchCompatibility.kt deleted file mode 100644 index 6b3f0229e..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/annotations/CastPatchCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.castbutton.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CastButtonCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt deleted file mode 100644 index f1925c0a3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/castbutton/patch/HideCastButtonPatch.kt +++ /dev/null @@ -1,57 +0,0 @@ -package app.revanced.patches.youtube.layout.castbutton.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@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(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_cast_button", - StringResource("revanced_hide_cast_button_title", "Hide cast button"), - true, - StringResource("revanced_hide_cast_button_summary_on", "Cast button is hidden"), - StringResource("revanced_hide_cast_button_summary_off", "Cast button is shown") - ) - ) - - with( - context.findClass("MediaRouteButton") - ?: return PatchResultError("MediaRouteButton class not found.") - ) { - with( - mutableClass.methods.find { it.name == "setVisibility" } - ?: return PatchResultError("setVisibility method not found.") - ) { - addInstructions( - 0, """ - invoke-static {p1}, Lapp/revanced/integrations/patches/HideCastButtonPatch;->getCastButtonOverrideV2(I)I - move-result p1 - """ - ) - } - } - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/annotations/CommentsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/comments/annotations/CommentsCompatibility.kt deleted file mode 100644 index fb1366158..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/annotations/CommentsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.comments.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CommentsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/bytecode/fingerprints/ShortsCommentsButtonFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/comments/bytecode/fingerprints/ShortsCommentsButtonFingerprint.kt deleted file mode 100644 index 878f11204..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/bytecode/fingerprints/ShortsCommentsButtonFingerprint.kt +++ /dev/null @@ -1,17 +0,0 @@ -package app.revanced.patches.youtube.layout.comments.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.comments.resource.patch.CommentsResourcePatch -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object ShortsCommentsButtonFingerprint : MethodFingerprint( - "V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("Z", "Z", "L"), - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { - it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == CommentsResourcePatch.shortsCommentsButtonId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/bytecode/patch/CommentsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/comments/bytecode/patch/CommentsPatch.kt deleted file mode 100644 index ddbcc7862..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/bytecode/patch/CommentsPatch.kt +++ /dev/null @@ -1,62 +0,0 @@ -package app.revanced.patches.youtube.layout.comments.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.comments.annotations.CommentsCompatibility -import app.revanced.patches.youtube.layout.comments.bytecode.fingerprints.ShortsCommentsButtonFingerprint -import app.revanced.patches.youtube.layout.comments.resource.patch.CommentsResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class, CommentsResourcePatch::class]) -@Name("comments") -@Description("Hides components related to comments.") -@CommentsCompatibility -@Version("0.0.1") -class CommentsPatch : BytecodePatch( - listOf( - ShortsCommentsButtonFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val shortsCommentsButtonResult = ShortsCommentsButtonFingerprint.result!! - val shortsCommentsButtonMethod = shortsCommentsButtonResult.mutableMethod - - val checkCastAnchorFingerprint = object : MethodFingerprint( - opcodes = listOf( - Opcode.CONST, - Opcode.CONST_HIGH16, - Opcode.IF_EQZ, - Opcode.CONST, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - ) - ) {} - - val checkCastAnchorIndex = checkCastAnchorFingerprint.also { - it.resolve(context, shortsCommentsButtonMethod, shortsCommentsButtonResult.classDef) - }.result!!.scanResult.patternScanResult!!.endIndex - - shortsCommentsButtonMethod.addInstructions( - checkCastAnchorIndex + 1, """ - invoke-static {v${(shortsCommentsButtonMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideShortsCommentsButtonPatch;->hideShortsCommentsButton(Landroid/view/View;)V - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/resource/patch/CommentsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/comments/resource/patch/CommentsResourcePatch.kt deleted file mode 100644 index 052b13059..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/comments/resource/patch/CommentsResourcePatch.kt +++ /dev/null @@ -1,64 +0,0 @@ -package app.revanced.patches.youtube.layout.comments.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.layout.comments.annotations.CommentsCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Name("comments-resource-patch") -@CommentsCompatibility -@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class CommentsResourcePatch : ResourcePatch { - companion object { - internal var shortsCommentsButtonId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - PreferenceScreen( - "revanced_comments", - StringResource("revanced_comments_title", "Comments"), - listOf( - SwitchPreference( - "revanced_hide_comments_section", - StringResource("revanced_hide_comments_section_title", "Hide comments section"), - false, - StringResource("revanced_hide_comments_section_summary_on", "Comment section is hidden"), - StringResource("revanced_hide_comments_section_summary_off", "Comment section is shown") - ), - SwitchPreference( - "revanced_hide_preview_comment", - StringResource("revanced_hide_preview_comment_title", "Hide preview comment"), - false, - StringResource("revanced_hide_preview_comment_on", "Preview comment is hidden"), - StringResource("revanced_hide_preview_comment_off", "Preview comment is shown") - ), - SwitchPreference( - "revanced_hide_shorts_comments_button", - StringResource("revanced_hide_shorts_comments_button_title", "Hide shorts comments button"), - false, - StringResource("revanced_hide_shorts_comments_button_on", "Shorts comments button is hidden"), - StringResource("revanced_hide_shorts_comments_button_off", "Shorts comments button is shown") - ), - ), - StringResource("revanced_comments_summary", "Manage the visibility of comments section components") - ) - ) - - shortsCommentsButtonId = ResourceMappingPatch.resourceMappings.single { - it.type == "drawable" && it.name == "ic_right_comment_32c" - }.id - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/flyoutpanel/patch/FlyoutPanelPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/flyoutpanel/patch/FlyoutPanelPatch.kt new file mode 100644 index 000000000..856173c45 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/flyoutpanel/patch/FlyoutPanelPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.flyoutpanel.flyoutpanel.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-flyout-panel") +@Description("Adds options to hide player settings flyout panel.") +@DependsOn( + [ + LithoFilterPatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class FlyoutPanelPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: FLYOUT_PANEL", + "SETTINGS: FLYOUT_PANEL_COMPONENT" + ) + + ResourceHelper.patchSuccess( + context, + "hide-flyout-panel" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/bytecode/fingerprints/QualityMenuViewInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/bytecode/fingerprints/QualityMenuViewInflateFingerprint.kt new file mode 100644 index 000000000..053dd6d84 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/bytecode/fingerprints/QualityMenuViewInflateFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode + +object QualityMenuViewInflateFingerprint : MethodFingerprint( + opcodes = listOf(Opcode.INVOKE_SUPER), + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.videoqualityfragmentLabelId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/bytecode/patch/OldQualityLayoutBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/bytecode/patch/OldQualityLayoutBytecodePatch.kt new file mode 100644 index 000000000..9e24ebbf0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/bytecode/patch/OldQualityLayoutBytecodePatch.kt @@ -0,0 +1,40 @@ +package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints.QualityMenuViewInflateFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.FLYOUTPANEL_LAYOUT +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction + +@Name("enable-oldstyle-quality-layout-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class OldQualityLayoutBytecodePatch : BytecodePatch( + listOf(QualityMenuViewInflateFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!! + val method = inflateFingerprintResult.mutableMethod + val instructions = method.implementation!!.instructions + + // at this index the listener is added to the list view + val listenerInvokeRegister = instructions.size - 1 - 1 + + // get the register which stores the quality menu list view + val onItemClickViewRegister = (instructions[listenerInvokeRegister] as FiveRegisterInstruction).registerC + + // insert the integrations method + method.addInstruction( + listenerInvokeRegister, // insert the integrations instructions right before the listener + "invoke-static { v$onItemClickViewRegister }, $FLYOUTPANEL_LAYOUT->enableOldQualityMenu(Landroid/widget/ListView;)V" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/resource/patch/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/resource/patch/OldQualityLayoutPatch.kt new file mode 100644 index 000000000..9c793c4cb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/flyoutpanel/oldqualitylayout/resource/patch/OldQualityLayoutPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.patch.OldQualityLayoutBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-oldstyle-quality-layout") +@Description("Enables the original quality flyout menu.") +@DependsOn( + [ + OldQualityLayoutBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class OldQualityLayoutPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: FLYOUT_PANEL", + "SETTINGS: ENABLE_OLD_STYLE_QUALITY_LAYOUT" + ) + + ResourceHelper.patchSuccess( + context, + "enable-oldstyle-quality-layout" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/endscreenoverlay/bytecode/patch/HideEndscreenOverlayBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/endscreenoverlay/bytecode/patch/HideEndscreenOverlayBytecodePatch.kt new file mode 100644 index 000000000..319fa12ae --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/endscreenoverlay/bytecode/patch/HideEndscreenOverlayBytecodePatch.kt @@ -0,0 +1,68 @@ +package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("hide-endscreen-overlay-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class HideEndscreenOverlayBytecodePatch : BytecodePatch() { + // list of resource names to get the id of + private val resourceIds = arrayOf( + "app_related_endscreen_results" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // end screen result + val insertIndex = index - 13 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.IF_NEZ) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA + mutableMethod.addInstructions( + insertIndex, """ + invoke-static {}, $FULLSCREEN_LAYOUT->hideEndscreenOverlay()Z + move-result v$dummyRegister + if-eqz v$dummyRegister, :on + return-void + """, listOf(ExternalLabel("on", mutableMethod.instruction(insertIndex))) + ) + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/endscreenoverlay/resource/patch/HideEndscreenOverlayPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/endscreenoverlay/resource/patch/HideEndscreenOverlayPatch.kt new file mode 100644 index 000000000..462cb3611 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/endscreenoverlay/resource/patch/HideEndscreenOverlayPatch.kt @@ -0,0 +1,50 @@ +package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.bytecode.patch.HideEndscreenOverlayBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources + +@Patch +@Name("hide-endscreen-overlay") +@Description("Hide endscreen overlay on swipe controls.") +@DependsOn( + [ + HideEndscreenOverlayBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideFilmStripPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: FULLSCREEN", + "SETTINGS: HIDE_ENDSCREEN_OVERLAY" + ) + + ResourceHelper.patchSuccess( + context, + "hide-endscreen-overlay" + ) + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/bytecode/fingerprints/ScrubbingLabelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/bytecode/fingerprints/ScrubbingLabelFingerprint.kt new file mode 100644 index 000000000..85378ad19 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/bytecode/fingerprints/ScrubbingLabelFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode + +object ScrubbingLabelFingerprint : MethodFingerprint( + opcodes = listOf(Opcode.IPUT_BOOLEAN), + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.scrubbingLabelId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/bytecode/patch/HideFilmstripOverlayBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/bytecode/patch/HideFilmstripOverlayBytecodePatch.kt new file mode 100644 index 000000000..9739bc807 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/bytecode/patch/HideFilmstripOverlayBytecodePatch.kt @@ -0,0 +1,56 @@ +package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.removeInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints.ScrubbingLabelFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.Opcode + +@Name("hide-filmstrip-overlay-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideFilmstripOverlayBytecodePatch : BytecodePatch( + listOf( + ScrubbingLabelFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val scrubbingLabelResult = ScrubbingLabelFingerprint.result!! + val scrubbingLabelMethod = scrubbingLabelResult.mutableMethod + val scrubbingLabelMethodInstructions = scrubbingLabelMethod.implementation!!.instructions + + for ((index, instruction) in scrubbingLabelMethodInstructions.withIndex()) { + if (instruction.opcode != Opcode.IPUT_BOOLEAN) continue + val scrubbingLabelRegisterA = (instruction as TwoRegisterInstruction).registerA + val scrubbingLabelRegisterB = scrubbingLabelRegisterA + 2 + val scrubbingLabelRegisterC = (instruction as TwoRegisterInstruction).registerB + val scrubbingLabelReference = (instruction as ReferenceInstruction).reference as FieldReference + + scrubbingLabelMethod.addInstructions( + index + 1, """ + invoke-static {}, $FULLSCREEN_LAYOUT->hideFilmstripOverlay()Z + move-result v$scrubbingLabelRegisterB + if-eqz v$scrubbingLabelRegisterB, :show + const/4 v$scrubbingLabelRegisterA, 0x0 + :show + iput-boolean v$scrubbingLabelRegisterA, v$scrubbingLabelRegisterC, ${scrubbingLabelReference.definingClass}->${scrubbingLabelReference.name}:${scrubbingLabelReference.type} + """ + ) + + scrubbingLabelMethod.removeInstruction(index) + break + } + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/resource/patch/HideFilmstripOverlayPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/resource/patch/HideFilmstripOverlayPatch.kt new file mode 100644 index 000000000..6b5f01bf6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/flimstripoverlay/resource/patch/HideFilmstripOverlayPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.patch.HideFilmstripOverlayBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-filmstrip-overlay") +@Description("Hide flimstrip overlay on swipe controls.") +@DependsOn( + [ + HideFilmstripOverlayBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideFilmstripOverlayPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: FULLSCREEN", + "SETTINGS: HIDE_FILMSTRIP_OVERLAY" + ) + + ResourceHelper.patchSuccess( + context, + "hide-filmstrip-overlay" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/fullscreenbuttoncontainer/bytecode/patch/FullscreenButtonContainerBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/fullscreenbuttoncontainer/bytecode/patch/FullscreenButtonContainerBytecodePatch.kt new file mode 100644 index 000000000..2599d26f7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/fullscreenbuttoncontainer/bytecode/patch/FullscreenButtonContainerBytecodePatch.kt @@ -0,0 +1,57 @@ +package app.revanced.patches.youtube.layout.fullscreen.fullscreenbuttoncontainer.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.Instruction21c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("hide-fullscreen-buttoncontainer-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class FullscreenButtonContainerBytecodePatch : BytecodePatch() { + private val resourceIds = arrayOf( + "quick_actions_element_container" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // fullscreen panel + val insertIndex = index + 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (invokeInstruction as Instruction21c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/FullscreenLayoutPatch", "hideFullscreenButtonContainer") + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/fullscreenbuttoncontainer/resource/patch/FullscreenButtonContainerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/fullscreenbuttoncontainer/resource/patch/FullscreenButtonContainerPatch.kt new file mode 100644 index 000000000..b83226830 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/fullscreenbuttoncontainer/resource/patch/FullscreenButtonContainerPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.fullscreen.fullscreenbuttoncontainer.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.fullscreen.fullscreenbuttoncontainer.bytecode.patch.FullscreenButtonContainerBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-fullscreen-buttoncontainer") +@Description("Hides the button containers in fullscreen.") +@DependsOn( + [ + FullscreenButtonContainerBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class FullscreenButtonContainerPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: FULLSCREEN", + "SETTINGS: HIDE_FULLSCREEN_BUTTON_CONTAINER" + ) + + ResourceHelper.patchSuccess( + context, + "hide-fullscreen-buttoncontainer" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/MarkerHapticsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/MarkerHapticsFingerprint.kt new file mode 100644 index 000000000..1305b4a8b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/MarkerHapticsFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object MarkerHapticsFingerprint : MethodFingerprint( + strings = listOf("Failed to execute markers haptics vibrate.") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/ScrubbingHapticsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/ScrubbingHapticsFingerprint.kt new file mode 100644 index 000000000..52b62ce1c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/ScrubbingHapticsFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object ScrubbingHapticsFingerprint : MethodFingerprint( + strings = listOf("Failed to haptics vibrate for fine scrubbing.") +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/SeekHapticsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/SeekHapticsFingerprint.kt new file mode 100644 index 000000000..4dd2bc3bd --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/SeekHapticsFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object SeekHapticsFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.CHECK_CAST, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.RETURN_VOID + ), + strings = listOf("Failed to easy seek haptics vibrate.") +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/ZoomHapticsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/ZoomHapticsFingerprint.kt new file mode 100644 index 000000000..295789ed5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/fingerprints/ZoomHapticsFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object ZoomHapticsFingerprint : MethodFingerprint( + strings = listOf("Failed to haptics vibrate for video zoom") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/patch/HapticFeedBackBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/patch/HapticFeedBackBytecodePatch.kt new file mode 100644 index 000000000..d231c0517 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/bytecode/patch/HapticFeedBackBytecodePatch.kt @@ -0,0 +1,88 @@ +package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.removeInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("disable-haptic-feedback-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HapticFeedBackBytecodePatch : BytecodePatch( + listOf( + MarkerHapticsFingerprint, + SeekHapticsFingerprint, + ScrubbingHapticsFingerprint, + ZoomHapticsFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + SeekHapticsFingerprint.disableHaptics("disableSeekVibrate") + ScrubbingHapticsFingerprint.voidHaptics("disableScrubbingVibrate") + MarkerHapticsFingerprint.voidHaptics("disableChapterVibrate") + ZoomHapticsFingerprint.voidHaptics("disableZoomVibrate") + + return PatchResultSuccess() + } + + private companion object { + fun MethodFingerprint.disableHaptics(targetMethodName: String) { + with(this.result!!) { + val startIndex = scanResult.patternScanResult!!.startIndex + val endIndex = scanResult.patternScanResult!!.endIndex + val insertIndex = endIndex + 4 + val targetRegister = (method.implementation!!.instructions.elementAt(insertIndex) as OneRegisterInstruction).registerA + val dummyRegister = targetRegister + 1 + + mutableMethod.removeInstruction(insertIndex) + + mutableMethod.addInstructions( + insertIndex, """ + invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z + move-result v$dummyRegister + if-eqz v$dummyRegister, :vibrate + const-wide/16 v$targetRegister, 0x0 + goto :exit + :vibrate + const-wide/16 v$targetRegister, 0x19 + """, listOf(ExternalLabel("exit", mutableMethod.instruction(insertIndex))) + ) + + mutableMethod.addInstructions( + startIndex, """ + invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z + move-result v$dummyRegister + if-eqz v$dummyRegister, :vibrate + return-void + """, listOf(ExternalLabel("vibrate", mutableMethod.instruction(startIndex))) + ) + } + } + + fun MethodFingerprint.voidHaptics(targetMethodName: String) { + with(this.result!!) { + mutableMethod.addInstructions( + 0, """ + invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z + move-result v0 + if-eqz v0, :vibrate + return-void + """, listOf(ExternalLabel("vibrate", mutableMethod.instruction(0))) + ) + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/resource/patch/HapticFeedBackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/resource/patch/HapticFeedBackPatch.kt new file mode 100644 index 000000000..f8b6e23fa --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreen/hapticfeedback/resource/patch/HapticFeedBackPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.patch.HapticFeedBackBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("disable-haptic-feedback") +@Description("Disable haptic feedback when swiping.") +@DependsOn( + [ + HapticFeedBackBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HapticFeedBackPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: FULLSCREEN", + "SETTINGS: DISABLE_HAPTIC_FEEDBACK" + ) + + ResourceHelper.patchSuccess( + context, + "disable-haptic-feedback" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/annotations/FullscreenPanelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/annotations/FullscreenPanelsCompatibility.kt deleted file mode 100644 index cd799d188..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/annotations/FullscreenPanelsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.fullscreenpanels.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class FullscreenPanelsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/fingerprints/FullscreenViewAdderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/fingerprints/FullscreenViewAdderFingerprint.kt deleted file mode 100644 index ef0769dfd..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/fingerprints/FullscreenViewAdderFingerprint.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object FullscreenViewAdderFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.IGET_BOOLEAN - ) -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/fingerprints/FullscreenViewAdderParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/fingerprints/FullscreenViewAdderParentFingerprint.kt deleted file mode 100644 index ad59ea905..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/fingerprints/FullscreenViewAdderParentFingerprint.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.youtube.layout.fullscreenpanels.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object FullscreenViewAdderParentFingerprint : MethodFingerprint( - parameters = listOf("L", "L"), - opcodes = listOf( - Opcode.GOTO, - Opcode.IGET_BOOLEAN, - Opcode.IF_EQ, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - ), - customFingerprint = { it.definingClass.endsWith("FullscreenEngagementPanelOverlay;") } -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt deleted file mode 100644 index e61de0f8c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/fullscreenpanels/patch/FullscreenPanelsRemoverPatch.kt +++ /dev/null @@ -1,65 +0,0 @@ -package app.revanced.patches.youtube.layout.fullscreenpanels.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.fullscreenpanels.annotations.FullscreenPanelsCompatibility -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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@Name("disable-fullscreen-panels") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Description("Disables video description and comments panel in fullscreen view.") -@FullscreenPanelsCompatibility -@Version("0.0.1") -class FullscreenPanelsRemoverPatch : BytecodePatch( - listOf( - FullscreenViewAdderParentFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_fullscreen_panels", - StringResource("revanced_hide_fullscreen_panels_title", "Hide fullscreen panels"), - true, - StringResource("revanced_hide_fullscreen_panels_summary_on", "Fullscreen panels are hidden"), - StringResource("revanced_hide_fullscreen_panels_summary_off", "Fullscreen panels are shown") - ) - ) - - val parentResult = FullscreenViewAdderParentFingerprint.result!! - FullscreenViewAdderFingerprint.resolve(context, parentResult.method, parentResult.classDef) - val result = FullscreenViewAdderParentFingerprint.result - ?: return PatchResultError("Fingerprint not resolved!") - - val method = result.mutableMethod - - val ifIndex = result.scanResult.patternScanResult!!.startIndex + 2 - - method.removeInstruction(ifIndex) - method.addInstructions( - ifIndex, """ - invoke-static {}, Lapp/revanced/integrations/patches/FullscreenPanelsRemoverPatch;->getFullscreenPanelsVisibility()I - move-result p1 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/StartVideoInformerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/fingerprints/StartVideoInformerFingerprint.kt similarity index 65% rename from src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/StartVideoInformerFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/fingerprints/StartVideoInformerFingerprint.kt index e65c2b74f..dfea63c3c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/StartVideoInformerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/fingerprints/StartVideoInformerFingerprint.kt @@ -1,13 +1,10 @@ -package app.revanced.patches.youtube.layout.autocaptions.fingerprints +package app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - -@FuzzyPatternScanMethod(3) object StartVideoInformerFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L", "L", "L"), listOf( Opcode.INVOKE_STATIC, @@ -22,12 +19,5 @@ object StartVideoInformerFingerprint : MethodFingerprint( Opcode.IGET_OBJECT, Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.CONST_4, - Opcode.IF_EQ, - Opcode.GOTO, ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/SubtitleTrackFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/fingerprints/SubtitleTrackFingerprint.kt similarity index 85% rename from src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/SubtitleTrackFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/fingerprints/SubtitleTrackFingerprint.kt index a011e60c2..5176bb937 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/SubtitleTrackFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/fingerprints/SubtitleTrackFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.autocaptions.fingerprints +package app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/patch/AutoCaptionsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/patch/AutoCaptionsBytecodePatch.kt new file mode 100644 index 000000000..4db27afd5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/bytecode/patch/AutoCaptionsBytecodePatch.kt @@ -0,0 +1,71 @@ +package app.revanced.patches.youtube.layout.general.autocaptions.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT + +@Name("hide-auto-captions-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class AutoCaptionsBytecodePatch : BytecodePatch( + listOf( + StartVideoInformerFingerprint, + SubtitleButtonControllerFingerprint, + SubtitleTrackFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + listOf( + StartVideoInformerFingerprint.toPatch(Status.DISABLED), + SubtitleButtonControllerFingerprint.toPatch(Status.ENABLED) + ).forEach { (fingerprint, status) -> + with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) { + mutableMethod.addInstructions( + 0, + """ + const/4 v0, ${status.value} + sput-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z + """ + ) + } + } + + val subtitleTrackMethod = SubtitleTrackFingerprint.result!!.mutableMethod + + subtitleTrackMethod.addInstructions( + 0, """ + invoke-static {}, $GENERAL_LAYOUT->hideAutoCaptions()Z + move-result v0 + if-eqz v0, :auto_captions_shown + sget-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z + if-nez v0, :auto_captions_shown + const/4 v0, 0x1 + return v0 + """, listOf(ExternalLabel("auto_captions_shown", subtitleTrackMethod.instruction(0))) + ) + + return PatchResultSuccess() + } + + private fun MethodFingerprint.toPatch(visibility: Status) = SetStatus(this, visibility) + + private data class SetStatus(val fingerprint: MethodFingerprint, val visibility: Status) + + private enum class Status(val value: Int) { + ENABLED(1), + DISABLED(0) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/resource/patch/AutoCaptionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/resource/patch/AutoCaptionsPatch.kt new file mode 100644 index 000000000..e77085930 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autocaptions/resource/patch/AutoCaptionsPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.autocaptions.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.patch.AutoCaptionsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-auto-captions") +@Description("Hide captions from being automatically enabled.") +@DependsOn( + [ + AutoCaptionsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class AutoCaptionsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_AUTO_CAPTIONS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-auto-captions" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/bytecode/fingerprints/EngagementPanelControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/bytecode/fingerprints/EngagementPanelControllerFingerprint.kt new file mode 100644 index 000000000..75b979f34 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/bytecode/fingerprints/EngagementPanelControllerFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object EngagementPanelControllerFingerprint : MethodFingerprint( + "L", + AccessFlags.PRIVATE or AccessFlags.FINAL, + strings = listOf( + "EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.", + "[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called." + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/bytecode/patch/PlayerPopupPanelsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/bytecode/patch/PlayerPopupPanelsBytecodePatch.kt new file mode 100644 index 000000000..c56f9bda9 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/bytecode/patch/PlayerPopupPanelsBytecodePatch.kt @@ -0,0 +1,40 @@ +package app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints.EngagementPanelControllerFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT + +@Name("hide-auto-player-popup-panels-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class PlayerPopupPanelsBytecodePatch : BytecodePatch( + listOf( + EngagementPanelControllerFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val engagementPanelControllerMethod = EngagementPanelControllerFingerprint.result!!.mutableMethod + + engagementPanelControllerMethod.addInstructions( + 0, """ + invoke-static { }, $GENERAL_LAYOUT->hideAutoPlayerPopupPanels()Z + move-result v0 + if-eqz v0, :player_popup_panels_shown + if-eqz p4, :player_popup_panels_shown + const/4 v0, 0x0 + return-object v0 + """, listOf(ExternalLabel("player_popup_panels_shown", engagementPanelControllerMethod.instruction(0))) + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/resource/patch/PlayerPopupPanelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/resource/patch/PlayerPopupPanelsPatch.kt new file mode 100644 index 000000000..4f13b89f8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/autopopuppanels/resource/patch/PlayerPopupPanelsPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.autopopuppanels.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.patch.PlayerPopupPanelsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-auto-player-popup-panels") +@Description("Hide automatic popup panels (playlist or live chat) on video player.") +@DependsOn( + [ + PlayerPopupPanelsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class PlayerPopupPanelsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_AUTO_PLAYER_POPUP_PANELS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-auto-player-popup-panels" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/crowdfundingbox/bytecode/patch/CrowdfundingBoxBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/crowdfundingbox/bytecode/patch/CrowdfundingBoxBytecodePatch.kt new file mode 100644 index 000000000..ceb7b21a6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/crowdfundingbox/bytecode/patch/CrowdfundingBoxBytecodePatch.kt @@ -0,0 +1,60 @@ +package app.revanced.patches.youtube.layout.general.crowdfundingbox.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("hide-crowdfunding-box-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class CrowdfundingBoxBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "donation_companion" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // crowdfunding + val insertIndex = index + 3 + val iPutInstruction = instructions.elementAt(insertIndex) + if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (iPutInstruction as Instruction22c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/GeneralLayoutPatch", "hideCrowdfundingBox") + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/crowdfundingbox/resource/patch/CrowdfundingBoxPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/crowdfundingbox/resource/patch/CrowdfundingBoxPatch.kt new file mode 100644 index 000000000..4a904ca79 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/crowdfundingbox/resource/patch/CrowdfundingBoxPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.crowdfundingbox.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.crowdfundingbox.bytecode.patch.CrowdfundingBoxBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-crowdfunding-box") +@Description("Hides the crowdfunding box between the player and video description.") +@DependsOn( + [ + CrowdfundingBoxBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class CrowdfundingBoxPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_CROWDFUNDING_BOX" + ) + + ResourceHelper.patchSuccess( + context, + "hide-crowdfunding-box" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/headerswitch/bytecode/patch/HeaderSwitchBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/headerswitch/bytecode/patch/HeaderSwitchBytecodePatch.kt new file mode 100644 index 000000000..e7fe90416 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/headerswitch/bytecode/patch/HeaderSwitchBytecodePatch.kt @@ -0,0 +1,63 @@ +package app.revanced.patches.youtube.layout.general.headerswitch.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.builder.MutableMethodImplementation +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@DependsOn([ResourceMappingPatch::class]) +@Name("header-switch-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HeaderSwitchBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "ytWordmarkHeader" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // header + val insertIndex = index + 1 + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (instructions.elementAt(index) as Instruction31i).registerA + + mutableMethod.addInstructions( + insertIndex, """ + invoke-static {v$viewRegister}, Lapp/revanced/integrations/patches/layout/GeneralLayoutPatch;->enablePremiumHeader(I)I + move-result v$viewRegister + """ + ) + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/headerswitch/resource/patch/HeaderSwitchPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/headerswitch/resource/patch/HeaderSwitchPatch.kt new file mode 100644 index 000000000..9b2b78fd5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/headerswitch/resource/patch/HeaderSwitchPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.headerswitch.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.headerswitch.bytecode.patch.HeaderSwitchBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("header-switch") +@Description("Add switch to change header.") +@DependsOn( + [ + HeaderSwitchBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HeaderSwitchPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HEADER_SWITCH" + ) + + ResourceHelper.patchSuccess( + context, + "header-switch" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/fingerprints/CreateMixPlaylistFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/CreateMixPlaylistFingerprint.kt similarity index 66% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/fingerprints/CreateMixPlaylistFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/CreateMixPlaylistFingerprint.kt index 01057978b..adda6b0de 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/fingerprints/CreateMixPlaylistFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/CreateMixPlaylistFingerprint.kt @@ -1,10 +1,16 @@ -package app.revanced.patches.youtube.layout.hidemixplaylists.fingerprints +package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.shared.annotation.YouTubeCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@Name("mix-playlists-first-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") object CreateMixPlaylistFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L", "L"), listOf( Opcode.INVOKE_DIRECT, @@ -19,6 +25,6 @@ object CreateMixPlaylistFingerprint : MethodFingerprint( Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT, - Opcode.INVOKE_VIRTUAL, + Opcode.INVOKE_VIRTUAL ) ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/FourthCreateMixPlaylistFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/FourthCreateMixPlaylistFingerprint.kt new file mode 100644 index 000000000..521e1fccb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/FourthCreateMixPlaylistFingerprint.kt @@ -0,0 +1,30 @@ +package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode + +@Name("mix-playlists-fourth-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") +object FourthCreateMixPlaylistFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.CONST, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.MOVE_OBJECT, + Opcode.CHECK_CAST + ), + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.abclistmenuitemLabelId + } == true + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/fingerprints/SecondCreateMixPlaylistFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/SecondCreateMixPlaylistFingerprint.kt similarity index 69% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/fingerprints/SecondCreateMixPlaylistFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/SecondCreateMixPlaylistFingerprint.kt index dcbb9069d..c164710ca 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/fingerprints/SecondCreateMixPlaylistFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/SecondCreateMixPlaylistFingerprint.kt @@ -1,10 +1,16 @@ -package app.revanced.patches.youtube.layout.hidemixplaylists.fingerprints +package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.shared.annotation.YouTubeCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +@Name("mix-playlists-second-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") object SecondCreateMixPlaylistFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L"), listOf( Opcode.INVOKE_DIRECT, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/ThirdCreateMixPlaylistFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/ThirdCreateMixPlaylistFingerprint.kt new file mode 100644 index 000000000..ae5309dc4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/fingerprints/ThirdCreateMixPlaylistFingerprint.kt @@ -0,0 +1,30 @@ +package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.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.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode + +@Name("mix-playlists-third-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") +object ThirdCreateMixPlaylistFingerprint : MethodFingerprint( + opcodes = listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IPUT_OBJECT + ), + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottompaneloverlaytextLabelId + } == true + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/patch/MixPlaylistsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/patch/MixPlaylistsBytecodePatch.kt new file mode 100644 index 000000000..d4672ccb9 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/bytecode/patch/MixPlaylistsBytecodePatch.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.util.bytecode.BytecodeHelper +import org.jf.dexlib2.iface.instruction.formats.Instruction21c +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction + +@Name("hide-mix-playlists-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class MixPlaylistsBytecodePatch : BytecodePatch( + listOf( + CreateMixPlaylistFingerprint, + SecondCreateMixPlaylistFingerprint, + ThirdCreateMixPlaylistFingerprint, + FourthCreateMixPlaylistFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + arrayOf(CreateMixPlaylistFingerprint, SecondCreateMixPlaylistFingerprint).forEach(::addHook) + ThirdCreateMixPlaylistFingerprint.hookMixPlaylists(true) + FourthCreateMixPlaylistFingerprint.hookMixPlaylists(false) + + return PatchResultSuccess() + } + + private fun addHook(fingerprint: MethodFingerprint) { + with (fingerprint.result!!) { + val insertIndex = scanResult.patternScanResult!!.endIndex - 3 + + val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA + + mutableMethod.implementation!!.injectHideCall(insertIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists") + } + } + + fun MethodFingerprint.hookMixPlaylists(isThirdFingerprint: Boolean) { + fun getRegister(instruction: Instruction): Int { + if (isThirdFingerprint) return (instruction as TwoRegisterInstruction).registerA + return (instruction as Instruction21c).registerA + } + with(this.result!!) { + val endIndex = scanResult.patternScanResult!!.endIndex + val instruction = method.implementation!!.instructions.elementAt(endIndex) + val register = getRegister(instruction) + + mutableMethod.implementation!!.injectHideCall(endIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists") + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/resource/patch/MixPlaylistsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/resource/patch/MixPlaylistsPatch.kt new file mode 100644 index 000000000..5734f479d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/mixplaylists/resource/patch/MixPlaylistsPatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.youtube.layout.general.mixplaylists.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.patch.MixPlaylistsBytecodePatch +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-mix-playlists") +@Description("Removes mix playlists from home feed and video player.") +@DependsOn( + [ + LithoFilterPatch::class, + MixPlaylistsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class MixPlaylistsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_MIX_PLAYLISTS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-mix-playlists" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt similarity index 59% rename from src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt index 0f9de4608..974a0da4d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/bytecode/fingerprints/AccountSwitcherAccessibilityLabelFingerprint.kt @@ -1,10 +1,16 @@ -package app.revanced.patches.youtube.layout.personalinformation.bytecode.fingerprints +package app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.personalinformation.resource.patch.HideEmailAddressResourcePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode +@Name("account-switcher-accessibility-label-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint( opcodes = listOf( Opcode.INVOKE_VIRTUAL, @@ -18,7 +24,7 @@ object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint( customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == HideEmailAddressResourcePatch.accountSwitcherAccessibilityLabelId + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accountSwitcherAccessibilityLabelId } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/bytecode/patch/HideEmailAddressPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/bytecode/patch/HideEmailAddressBytecodePatch.kt similarity index 58% rename from src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/bytecode/patch/HideEmailAddressPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/bytecode/patch/HideEmailAddressBytecodePatch.kt index 46234db58..7a1d1b670 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/bytecode/patch/HideEmailAddressPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/bytecode/patch/HideEmailAddressBytecodePatch.kt @@ -1,6 +1,5 @@ -package app.revanced.patches.youtube.layout.personalinformation.bytecode.patch +package app.revanced.patches.youtube.layout.general.personalinformation.bytecode.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext @@ -9,22 +8,16 @@ import app.revanced.patcher.extensions.instruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.layout.personalinformation.annotations.HideEmailAddressCompatibility -import app.revanced.patches.youtube.layout.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint -import app.revanced.patches.youtube.layout.personalinformation.resource.patch.HideEmailAddressResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -@Patch -@DependsOn([IntegrationsPatch::class, HideEmailAddressResourcePatch::class]) -@Name("hide-email-address") -@Description("Hides the email address in the account switcher.") -@HideEmailAddressCompatibility +@Name("hide-email-address-bytecode-patch") +@YouTubeCompatibility @Version("0.0.1") -class HideEmailAddressPatch : BytecodePatch( +class HideEmailAddressBytecodePatch : BytecodePatch( listOf( AccountSwitcherAccessibilityLabelFingerprint ) @@ -43,7 +36,7 @@ class HideEmailAddressPatch : BytecodePatch( accountSwitcherAccessibilityLabelMethod.addInstructions( setVisibilityConstIndex, """ - invoke-static {v$setVisibilityConstRegister}, Lapp/revanced/integrations/patches/HideEmailAddressPatch;->hideEmailAddress(I)I + invoke-static {v$setVisibilityConstRegister}, $GENERAL_LAYOUT->hideEmailAddress(I)I move-result v$setVisibilityConstRegister """ ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/resource/patch/HideEmailAddressPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/resource/patch/HideEmailAddressPatch.kt new file mode 100644 index 000000000..89031d74d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/personalinformation/resource/patch/HideEmailAddressPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.personalinformation.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.patch.HideEmailAddressBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-email-address") +@Description("Hides the email address in the account switcher.") +@DependsOn( + [ + HideEmailAddressBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideEmailAddressPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_EMAIL_ADDRESS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-email-address" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/bytecode/fingerprints/PivotBarCreateButtonViewFingerprint.kt similarity index 79% rename from src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/bytecode/fingerprints/PivotBarCreateButtonViewFingerprint.kt index 8be27c38a..e765d8e97 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/fingerprints/PivotBarCreateButtonViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/bytecode/fingerprints/PivotBarCreateButtonViewFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.pivotbar.createbutton.fingerprints +package app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/bytecode/patch/CreateButtonRemoverBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/bytecode/patch/CreateButtonRemoverBytecodePatch.kt new file mode 100644 index 000000000..bf3576a5b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/bytecode/patch/CreateButtonRemoverBytecodePatch.kt @@ -0,0 +1,50 @@ +package app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.fingerprints.PivotBarCreateButtonViewFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.fingerprints.PivotBarFingerprint +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT +import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook +import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT + +@Name("hide-create-button-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class CreateButtonRemoverBytecodePatch : BytecodePatch( + listOf(PivotBarFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + + /* + * Resolve fingerprints + */ + + val pivotBarResult = PivotBarFingerprint.result ?: return PatchResultError("PivotBarFingerprint failed") + + if (!PivotBarCreateButtonViewFingerprint.resolve(context, pivotBarResult.mutableMethod, pivotBarResult.mutableClass)) + return PatchResultError("${PivotBarCreateButtonViewFingerprint.name} failed") + + val createButtonResult = PivotBarCreateButtonViewFingerprint.result!! + val insertIndex = createButtonResult.scanResult.patternScanResult!!.endIndex + + /* + * Inject hooks + */ + + val hook = + "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT->hideCreateButton(Landroid/view/View;)V" + + createButtonResult.mutableMethod.injectHook(hook, insertIndex) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/resource/patch/CreateButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/resource/patch/CreateButtonRemoverPatch.kt new file mode 100644 index 000000000..a4ca3d7b6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/createbutton/resource/patch/CreateButtonRemoverPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.pivotbar.createbutton.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.pivotbar.createbutton.bytecode.patch.CreateButtonRemoverBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-create-button") +@Description("Hides the create button in the navigation bar.") +@DependsOn( + [ + CreateButtonRemoverBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class CreateButtonRemoverPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_CREATE_BUTTON" + ) + + ResourceHelper.patchSuccess( + context, + "hide-create-button" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/fingerprints/PivotBarEnumFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/fingerprints/PivotBarEnumFingerprint.kt similarity index 79% rename from src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/fingerprints/PivotBarEnumFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/fingerprints/PivotBarEnumFingerprint.kt index 770d63c37..01b850689 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/fingerprints/PivotBarEnumFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/fingerprints/PivotBarEnumFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.pivotbar.shortsbutton.fingerprints +package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/fingerprints/PivotBarShortsButtonViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/fingerprints/PivotBarShortsButtonViewFingerprint.kt similarity index 76% rename from src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/fingerprints/PivotBarShortsButtonViewFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/fingerprints/PivotBarShortsButtonViewFingerprint.kt index cfa5e93ba..cd3734980 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/fingerprints/PivotBarShortsButtonViewFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/fingerprints/PivotBarShortsButtonViewFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.pivotbar.shortsbutton.fingerprints +package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/patch/ShortsButtonRemoverBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/patch/ShortsButtonRemoverBytecodePatch.kt new file mode 100644 index 000000000..7388a62a6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/bytecode/patch/ShortsButtonRemoverBytecodePatch.kt @@ -0,0 +1,70 @@ +package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarEnumFingerprint +import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarShortsButtonViewFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.fingerprints.PivotBarFingerprint +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT +import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook +import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT + +@Name("hide-shorts-button") +@YouTubeCompatibility +@Version("0.0.1") +class ShortsButtonRemoverBytecodePatch : BytecodePatch( + listOf(PivotBarFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + + /* + * Resolve fingerprints + */ + + val pivotBarResult = PivotBarFingerprint.result ?: return PatchResultError("PivotBarFingerprint failed") + val fingerprintResults = arrayOf(PivotBarEnumFingerprint, PivotBarShortsButtonViewFingerprint) + .onEach { + val resolutionSucceeded = it.resolve( + context, + pivotBarResult.mutableMethod, + pivotBarResult.mutableClass + ) + + if (!resolutionSucceeded) return PatchResultError("${it.name} failed") + } + .map { it.result!!.scanResult.patternScanResult!! } + + val enumScanResult = fingerprintResults[0] + val buttonViewResult = fingerprintResults[1] + + val enumHookInsertIndex = enumScanResult.startIndex + 2 + val buttonHookInsertIndex = buttonViewResult.endIndex + + /* + * Inject hooks + */ + + val enumHook = + "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, $GENERAL_LAYOUT->lastPivotTab:Ljava/lang/Enum;" + val buttonHook = + "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT->hideShortsButton(Landroid/view/View;)V" + + // Inject bottom to top to not mess up the indices + mapOf( + buttonHook to buttonHookInsertIndex, + enumHook to enumHookInsertIndex + ).forEach { (hook, insertIndex) -> + pivotBarResult.mutableMethod.injectHook(hook, insertIndex) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/resource/patch/ShortsButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/resource/patch/ShortsButtonRemoverPatch.kt new file mode 100644 index 000000000..2e71baefe --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/pivotbar/shortsbutton/resource/patch/ShortsButtonRemoverPatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.patch.ShortsButtonRemoverBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-shorts-button") +@Description("Hides the shorts button in the navigation bar.") +@DependsOn( + [ + ShortsButtonRemoverBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ShortsButtonRemoverPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings4( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: SHORTS_COMPONENT.PARENT", + "SETTINGS: SHORTS_COMPONENT_PARENT.A", + "SETTINGS: HIDE_SHORTS_BUTTON" + ) + + ResourceHelper.patchSuccess( + context, + "hide-shorts-button" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/shortscomponent/bytecode/patch/ShortsComponentBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/shortscomponent/bytecode/patch/ShortsComponentBytecodePatch.kt new file mode 100644 index 000000000..4ef6fb321 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/shortscomponent/bytecode/patch/ShortsComponentBytecodePatch.kt @@ -0,0 +1,88 @@ +package app.revanced.patches.youtube.layout.general.shortscomponent.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.bytecode.BytecodeHelper +import org.jf.dexlib2.iface.instruction.formats.Instruction21c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.Opcode + +@Name("hide-shorts-component-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class ShortsComponentBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "ic_right_comment_32c", + "reel_dyn_remix", + "reel_player_paused_state_buttons" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // shorts player comment + val insertIndex = index - 2 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CONST_HIGH16) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (instructions.elementAt(index + 3) as OneRegisterInstruction).registerA + mutableMethod.implementation!!.injectHideCall(index + 4, viewRegister, "layout/GeneralLayoutPatch", "hideShortsPlayerCommentsButton") + } + + resourceIds[1] -> { // shorts player remix + val insertIndex = index - 2 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (invokeInstruction as Instruction21c).registerA + mutableMethod.implementation!!.injectHideCall(index - 1, viewRegister, "layout/GeneralLayoutPatch", "hideShortsPlayerRemixButton") + } + + resourceIds[2] -> { // shorts player subscriptions banner + val insertIndex = index + 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (invokeInstruction as Instruction21c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/GeneralLayoutPatch", "hideShortsPlayerSubscriptionsButton") + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + + BytecodeHelper.patchStatus(context, "ShortsComponent") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/shortscomponent/resource/patch/ShortsComponentPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/shortscomponent/resource/patch/ShortsComponentPatch.kt new file mode 100644 index 000000000..e670ba22e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/shortscomponent/resource/patch/ShortsComponentPatch.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.youtube.layout.general.shortscomponent.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.shortscomponent.bytecode.patch.ShortsComponentBytecodePatch +import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-shorts-component") +@Description("Hides other Shorts components.") +@DependsOn( + [ + LithoFilterPatch::class, + ShortsComponentBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ShortsComponentPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings5( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: SHORTS_COMPONENT.PARENT", + "SETTINGS: SHORTS_COMPONENT_PARENT.A", + "SETTINGS: SHORTS_COMPONENT_PARENT.B", + "SETTINGS: HIDE_SHORTS_COMPONENTS" + ) + + ResourceHelper.addSettings4( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: SHORTS_COMPONENT.PARENT", + "SETTINGS: SHORTS_COMPONENT_PARENT.A", + "SETTINGS: HIDE_SHORTS_SHELF" + ) + + ResourceHelper.patchSuccess( + context, + "hide-shorts-component" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/bytecode/fingerprints/UserWasInShortsFingerprint.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/bytecode/fingerprints/UserWasInShortsFingerprint.kt index a994a26d6..dde2205b7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/fingerprints/UserWasInShortsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/bytecode/fingerprints/UserWasInShortsFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.startupshortsreset.fingerprints +package app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(3) object UserWasInShortsFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/bytecode/patch/HideShortsOnStartupBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/bytecode/patch/HideShortsOnStartupBytecodePatch.kt new file mode 100644 index 000000000..60b8347c1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/bytecode/patch/HideShortsOnStartupBytecodePatch.kt @@ -0,0 +1,41 @@ +package app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.fingerprints.UserWasInShortsFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("hide-startup-shorts-player-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideShortsOnStartupBytecodePatch : BytecodePatch( + listOf( + UserWasInShortsFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val userWasInShortsResult = UserWasInShortsFingerprint.result!! + val userWasInShortsMethod = userWasInShortsResult.mutableMethod + val moveResultIndex = userWasInShortsResult.scanResult.patternScanResult!!.endIndex + + userWasInShortsMethod.addInstructions( + moveResultIndex + 1, """ + invoke-static { }, $GENERAL_LAYOUT->hideStartupShortsPlayer()Z + move-result v5 + if-eqz v5, :show_startup_shorts_player + return-void + """, listOf(ExternalLabel("show_startup_shorts_player", userWasInShortsMethod.instruction(moveResultIndex + 1))) + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/resource/patch/HideShortsOnStartupPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/resource/patch/HideShortsOnStartupPatch.kt new file mode 100644 index 000000000..d6781c2e4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/startupshortsreset/resource/patch/HideShortsOnStartupPatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.youtube.layout.general.startupshortsreset.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.patch.HideShortsOnStartupBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-startup-shorts-player") +@Description("Disables playing YouTube Shorts when launching YouTube.") +@DependsOn( + [ + HideShortsOnStartupBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideShortsOnStartupPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings4( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: SHORTS_COMPONENT.PARENT", + "SETTINGS: SHORTS_COMPONENT_PARENT.B", + "SETTINGS: HIDE_STARTUP_SHORTS_PLAYER" + ) + + ResourceHelper.patchSuccess( + context, + "hide-startup-shorts-player" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/stories/bytecode/patch/HideStoriesBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/stories/bytecode/patch/HideStoriesBytecodePatch.kt new file mode 100644 index 000000000..381eae6b8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/stories/bytecode/patch/HideStoriesBytecodePatch.kt @@ -0,0 +1,61 @@ +package app.revanced.patches.youtube.layout.general.stories.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("hide-stories-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class HideStoriesBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "reel_multiple_items_shelf", + "reel_item_container" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0], resourceIds[1] -> { // reel ads + val insertIndex = index + 4 + val iPutInstruction = instructions.elementAt(insertIndex) + if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (iPutInstruction as Instruction22c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/GeneralLayoutPatch", "hideStoriesShelf") + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/stories/resource/patch/HideStoriesPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/stories/resource/patch/HideStoriesPatch.kt new file mode 100644 index 000000000..45766198d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/stories/resource/patch/HideStoriesPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.stories.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.stories.bytecode.patch.HideStoriesBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-stories") +@Description("Hides YouTube Stories shelf on the feed.") +@DependsOn( + [ + HideStoriesBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideStoriesPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: HIDE_STORIES_SHELF" + ) + + ResourceHelper.patchSuccess( + context, + "hide-stories" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt index a378eaf65..266bf7dd7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerDimensionsCalculatorFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints +package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) // TODO: Find a good threshold value object MiniPlayerDimensionsCalculatorFingerprint : MethodFingerprint( "V", diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerOverrideFingerprint.kt similarity index 79% rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerOverrideFingerprint.kt index 59350da28..f4841d17c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerOverrideFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints +package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt index aba50b3d4..302973df5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerOverrideNoContextFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints +package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt index e4777c4c1..e95e919a0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/fingerprints/MiniPlayerResponseModelSizeCheckFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints +package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/patch/TabletMiniPlayerBytecodePatch.kt similarity index 60% rename from src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/patch/TabletMiniPlayerBytecodePatch.kt index 6f0b2a5f1..ac8687f8b 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/patch/TabletMiniPlayerPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/bytecode/patch/TabletMiniPlayerBytecodePatch.kt @@ -1,6 +1,5 @@ -package app.revanced.patches.youtube.layout.tabletminiplayer.patch +package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext @@ -10,43 +9,25 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion. import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.layout.tabletminiplayer.annotations.TabletMiniPlayerCompatibility -import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerDimensionsCalculatorFingerprint -import app.revanced.patches.youtube.layout.tabletminiplayer.fingerprints.MiniPlayerOverrideFingerprint -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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference +import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerDimensionsCalculatorFingerprint +import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerOverrideFingerprint +import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerOverrideNoContextFingerprint +import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("tablet-mini-player") -@Description("Enables the tablet mini player layout.") -@TabletMiniPlayerCompatibility +@Name("enable-tablet-miniplayer-bytecode-patch") +@YouTubeCompatibility @Version("0.0.1") -class TabletMiniPlayerPatch : BytecodePatch( +class TabletMiniPlayerBytecodePatch : BytecodePatch( listOf( MiniPlayerDimensionsCalculatorFingerprint, MiniPlayerResponseModelSizeCheckFingerprint ) ) { override fun execute(context: BytecodeContext): 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 @@ -86,7 +67,7 @@ class TabletMiniPlayerPatch : BytecodePatch( this.addInstructions( index, """ - invoke-static {v$overrideRegister}, Lapp/revanced/integrations/patches/TabletMiniPlayerOverridePatch;->getTabletMiniPlayerOverride(Z)Z + invoke-static {v$overrideRegister}, $GENERAL_LAYOUT->enableTabletMiniPlayer(Z)Z move-result v$overrideRegister """ ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/resource/patch/TabletMiniPlayerPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/resource/patch/TabletMiniPlayerPatch.kt new file mode 100644 index 000000000..22c608524 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/tabletminiplayer/resource/patch/TabletMiniPlayerPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.tabletminiplayer.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.patch.TabletMiniPlayerBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-tablet-miniplayer") +@Description("Enables the tablet mini player layout.") +@DependsOn( + [ + TabletMiniPlayerBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class TabletMiniPlayerPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: ENABLE_TABLET_MINIPLAYER" + ) + + ResourceHelper.patchSuccess( + context, + "enable-tablet-miniplayer" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarOneFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarOneFingerprint.kt new file mode 100644 index 000000000..34905feec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarOneFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object WideSearchbarOneFingerprint : MethodFingerprint( + "L",AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L"), listOf( + Opcode.IF_NEZ, + Opcode.SGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.INVOKE_STATIC + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarOneParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarOneParentFingerprint.kt new file mode 100644 index 000000000..5b040063a --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarOneParentFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object WideSearchbarOneParentFingerprint : MethodFingerprint( + "V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("L"), + strings = listOf("FEhistory", "FEmy_videos", "FEpurchases") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarTwoFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarTwoFingerprint.kt new file mode 100644 index 000000000..91f881fc7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarTwoFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object WideSearchbarTwoFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.NEW_INSTANCE + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarTwoParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarTwoParentFingerprint.kt new file mode 100644 index 000000000..ae5bc5d9f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/fingerprints/WideSearchbarTwoParentFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object WideSearchbarTwoParentFingerprint : MethodFingerprint( + "L", + AccessFlags.PUBLIC or AccessFlags.STATIC, + strings = listOf( + "Callback already registered.", + "Failed to create SpotlightModeController." + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/patch/WideSearchbarBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/patch/WideSearchbarBytecodePatch.kt new file mode 100644 index 000000000..c38b50179 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/bytecode/patch/WideSearchbarBytecodePatch.kt @@ -0,0 +1,61 @@ +package app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarOneFingerprint +import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarOneParentFingerprint +import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarTwoFingerprint +import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarTwoParentFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT + +@Name("enable-wide-searchbar-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class WideSearchbarBytecodePatch : BytecodePatch( + listOf( + WideSearchbarOneParentFingerprint, WideSearchbarTwoParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + WideSearchbarOneFingerprint.resolve(context, WideSearchbarOneParentFingerprint.result!!.classDef) + WideSearchbarTwoFingerprint.resolve(context, WideSearchbarTwoParentFingerprint.result!!.classDef) + + val resultOne = WideSearchbarOneFingerprint.result + val targetMethodOne = + context + .toMethodWalker(resultOne!!.method) + .nextMethod(resultOne.scanResult.patternScanResult!!.endIndex, true) + .getMethod() as MutableMethod + + + val resultTwo = WideSearchbarTwoFingerprint.result + val targetMethodTwo = + context.toMethodWalker(resultTwo!!.method) + .nextMethod(resultTwo.scanResult.patternScanResult!!.startIndex, true) + .getMethod() as MutableMethod + + injectSearchBarHook(targetMethodOne) + injectSearchBarHook(targetMethodTwo) + + return PatchResultSuccess() + } + + private fun injectSearchBarHook(method: MutableMethod) { + val index = method.implementation!!.instructions.size - 1 + method.addInstructions( + index, """ + invoke-static {}, $GENERAL_LAYOUT->enableWideSearchbar()Z + move-result p0 + """ + ) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/resource/patch/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/resource/patch/WideSearchbarPatch.kt new file mode 100644 index 000000000..c75d91033 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/general/widesearchbar/resource/patch/WideSearchbarPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.general.widesearchbar.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.patch.WideSearchbarBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-wide-searchbar") +@Description("Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.") +@DependsOn( + [ + WideSearchbarBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class WideSearchbarPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: GENERAL", + "SETTINGS: ENABLE_WIDE_SEARCHBAR" + ) + + ResourceHelper.patchSuccess( + context, + "enable-wide-searchbar" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/annotations/AlbumCardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/annotations/AlbumCardsCompatibility.kt deleted file mode 100644 index d82f26e27..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/annotations/AlbumCardsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.hidealbumcards.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class AlbumCardsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/bytecode/patch/AlbumCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/bytecode/patch/AlbumCardsPatch.kt deleted file mode 100644 index 9d7593d9a..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/bytecode/patch/AlbumCardsPatch.kt +++ /dev/null @@ -1,45 +0,0 @@ -package app.revanced.patches.youtube.layout.hidealbumcards.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.hidealbumcards.annotations.AlbumCardsCompatibility -import app.revanced.patches.youtube.layout.hidealbumcards.bytecode.fingerprints.AlbumCardsFingerprint -import app.revanced.patches.youtube.layout.hidealbumcards.resource.patch.AlbumCardsResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class, AlbumCardsResourcePatch::class]) -@Name("hide-album-cards") -@Description("Hides the album cards below the artist description.") -@AlbumCardsCompatibility -@Version("0.0.1") -class AlbumCardsPatch : BytecodePatch( - listOf( - AlbumCardsFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val albumCardsResult = AlbumCardsFingerprint.result!! - val albumCardsMethod = albumCardsResult.mutableMethod - - val checkCastAnchorIndex = albumCardsResult.scanResult.patternScanResult!!.endIndex - - albumCardsMethod.addInstruction( - checkCastAnchorIndex + 1, """ - invoke-static {v${(albumCardsMethod.instruction(checkCastAnchorIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideAlbumCardsPatch;->hideAlbumCards(Landroid/view/View;)V - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/resource/patch/AlbumCardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/resource/patch/AlbumCardsResourcePatch.kt deleted file mode 100644 index faf757593..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/resource/patch/AlbumCardsResourcePatch.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.youtube.layout.hidealbumcards.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.layout.hidealbumcards.annotations.AlbumCardsCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Name("hide-album-cards-resource-patch") -@AlbumCardsCompatibility -@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class AlbumCardsResourcePatch : ResourcePatch { - companion object { - internal var albumCardId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_album_cards", - StringResource("revanced_hide_album_cards_title", "Hide album cards"), - false, - StringResource("revanced_hide_album_cards_summary_on", "Music album cards are hidden"), - StringResource("revanced_hide_album_cards_summary_off", "Music album cards are shown") - ) - ) - - albumCardId = ResourceMappingPatch.resourceMappings.single { - it.type == "layout" && it.name == "album_card" - }.id - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideartistcard/annotations/HideArtistCardCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideartistcard/annotations/HideArtistCardCompatibility.kt deleted file mode 100644 index 6bbe049cf..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideartistcard/annotations/HideArtistCardCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.buttons.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideArtistCardCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideartistcard/patch/HideArtistCardPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideartistcard/patch/HideArtistCardPatch.kt deleted file mode 100644 index 9b7ff77e1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideartistcard/patch/HideArtistCardPatch.kt +++ /dev/null @@ -1,38 +0,0 @@ -package app.revanced.patches.youtube.layout.hideartistcard.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.litho.filter.patch.LithoFilterPatch -import app.revanced.patches.youtube.layout.buttons.annotations.HideArtistCardCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([ResourceMappingPatch::class, LithoFilterPatch::class]) -@Name("hide-artist-card") -@Description("Hides the artist card below the searchbar.") -@HideArtistCardCompatibility -@Version("0.0.1") -class HideArtistCardPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_artist_card", - StringResource("revanced_hide_hide_artist_card_title", "Hide artist card"), - false, - StringResource("revanced_hide_hide_artist_card_on", "Artist card is hidden"), - StringResource("revanced_hide_hide_artist_card_off", "Artist card is shown") - ), - ) - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecaptionsbutton/patch/HideCaptionsButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidecaptionsbutton/patch/HideCaptionsButtonPatch.kt deleted file mode 100644 index a2500367b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecaptionsbutton/patch/HideCaptionsButtonPatch.kt +++ /dev/null @@ -1,56 +0,0 @@ -package app.revanced.patches.youtube.layout.hidecaptionsbutton.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.autocaptions.annotations.AutoCaptionsCompatibility -import app.revanced.patches.youtube.layout.autocaptions.fingerprints.SubtitleButtonControllerFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.Opcode - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("hide-captions-button") -@Description("Hides the captions button on video player.") -@AutoCaptionsCompatibility -@Version("0.0.1") -class HideCaptionsButtonPatch : BytecodePatch(listOf( - SubtitleButtonControllerFingerprint, -)) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_captions_button", - StringResource("revanced_hide_captions_button_title", "Hide captions button"), - false, - StringResource("revanced_hide_captions_button_summary_on", "Captions button is hidden"), - StringResource("revanced_hide_captions_button_summary_off", "Captions button is shown") - ) - ) - - val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod - - // Due to previously applied patches, scanResult index cannot be used in this context - val igetBooleanIndex = subtitleButtonControllerMethod.implementation!!.instructions.indexOfFirst { - it.opcode == Opcode.IGET_BOOLEAN - } - - subtitleButtonControllerMethod.addInstructions( - igetBooleanIndex + 1, """ - invoke-static {v0}, Lapp/revanced/integrations/patches/HideCaptionsButtonPatch;->hideCaptionsButton(Landroid/widget/ImageView;)V - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt deleted file mode 100644 index 455ef57e2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/annotations/CrowdfundingBoxCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.hidecrowdfundingbox.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CrowdfundingBoxCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt deleted file mode 100644 index ff76e7b24..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/bytecode/fingerprints/CrowdfundingBoxFingerprint.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.youtube.layout.hidecrowdfundingbox.bytecode.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hidecrowdfundingbox.resource.patch.CrowdfundingBoxResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object CrowdfundingBoxFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.CONST_4, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.CONST, - ), - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { instruction -> - instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == CrowdfundingBoxResourcePatch.crowdfundingBoxId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt deleted file mode 100644 index 00583184c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/bytecode/patch/CrowdfundingBoxPatch.kt +++ /dev/null @@ -1,46 +0,0 @@ -package app.revanced.patches.youtube.layout.hidecrowdfundingbox.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.hidecrowdfundingbox.resource.patch.CrowdfundingBoxResourcePatch -import app.revanced.patches.youtube.layout.hidecrowdfundingbox.annotations.CrowdfundingBoxCompatibility -import app.revanced.patches.youtube.layout.hidecrowdfundingbox.bytecode.fingerprints.CrowdfundingBoxFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class, CrowdfundingBoxResourcePatch::class]) -@Name("hide-crowdfunding-box") -@Description("Hides the crowdfunding box between the player and video description.") -@CrowdfundingBoxCompatibility -@Version("0.0.1") -class CrowdfundingBoxPatch : BytecodePatch( - listOf( - CrowdfundingBoxFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - val crowdfundingBoxResult = CrowdfundingBoxFingerprint.result!! - val crowdfundingBoxMethod = crowdfundingBoxResult.mutableMethod - - val moveResultObjectIndex = - crowdfundingBoxResult.scanResult.patternScanResult!!.endIndex - 2 - - crowdfundingBoxMethod.addInstruction( - moveResultObjectIndex + 1, """ - invoke-static {v${(crowdfundingBoxMethod.instruction(moveResultObjectIndex) as OneRegisterInstruction).registerA}}, Lapp/revanced/integrations/patches/HideCrowdfundingBoxPatch;->hideCrowdfundingBox(Landroid/view/View;)V - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt deleted file mode 100644 index 2529b26b8..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidecrowdfundingbox/resource/patch/CrowdfundingBoxResourcePatch.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.youtube.layout.hidecrowdfundingbox.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.layout.hidecrowdfundingbox.annotations.CrowdfundingBoxCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Name("crowdfunding-box-resource-patch") -@CrowdfundingBoxCompatibility -@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class CrowdfundingBoxResourcePatch : ResourcePatch { - companion object { - internal var crowdfundingBoxId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_crowdfunding_box", - StringResource("revanced_hide_crowdfunding_box_title", "Hide crowdfunding box"), - false, - StringResource("revanced_hide_crowdfunding_box_summary_on", "Crowdfunding box is hidden"), - StringResource("revanced_hide_crowdfunding_box_summary_off", "Crowdfunding box is shown") - ) - ) - - crowdfundingBoxId = ResourceMappingPatch.resourceMappings.single { - it.type == "layout" && it.name == "donation_companion" - }.id - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/annotations/HideEndScreenCardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/annotations/HideEndScreenCardsCompatibility.kt deleted file mode 100644 index 03101c79c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/annotations/HideEndScreenCardsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.hideendscreencards.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideEndscreenCardsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/patch/HideEndscreenCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/patch/HideEndscreenCardsPatch.kt deleted file mode 100644 index 8bef7a928..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/patch/HideEndscreenCardsPatch.kt +++ /dev/null @@ -1,57 +0,0 @@ -package app.revanced.patches.youtube.layout.hideendscreencards.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.Fingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.layout.hideendscreencards.annotations.HideEndscreenCardsCompatibility -import app.revanced.patches.youtube.layout.hideendscreencards.bytecode.fingerprints.LayoutCircleFingerprint -import app.revanced.patches.youtube.layout.hideendscreencards.bytecode.fingerprints.LayoutIconFingerprint -import app.revanced.patches.youtube.layout.hideendscreencards.bytecode.fingerprints.LayoutVideoFingerprint -import app.revanced.patches.youtube.layout.hideendscreencards.resource.patch.HideEndscreenCardsResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.iface.instruction.formats.Instruction21c - -@Patch -@DependsOn([IntegrationsPatch::class, HideEndscreenCardsResourcePatch::class]) -@Name("hide-endscreen-cards") -@Description("Hides the suggested video cards at the end of a video in fullscreen.") -@HideEndscreenCardsCompatibility -@Version("0.0.1") -class HideEndscreenCardsPatch : BytecodePatch( - listOf( - LayoutCircleFingerprint, - LayoutIconFingerprint, - LayoutVideoFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - fun MethodFingerprint.injectHideCall() { - val layoutResult = result!! - val layoutMethod = layoutResult.mutableMethod - - val checkCastIndex = layoutResult.scanResult.patternScanResult!!.endIndex - val viewRegister = (layoutMethod.instruction(checkCastIndex) as Instruction21c).registerA - - layoutMethod.addInstruction( - checkCastIndex + 1, - "invoke-static { v$viewRegister }, Lapp/revanced/integrations/patches/HideEndscreenCardsPatch;->hideEndscreen(Landroid/view/View;)V" - ) - } - - listOf(LayoutCircleFingerprint, LayoutIconFingerprint, LayoutVideoFingerprint).forEach(MethodFingerprint::injectHideCall) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt deleted file mode 100644 index 949e5847a..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/resource/patch/HideEndscreenCardsResourcePatch.kt +++ /dev/null @@ -1,48 +0,0 @@ -package app.revanced.patches.youtube.layout.hideendscreencards.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.layout.hideendscreencards.annotations.HideEndscreenCardsCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Name("hide-endscreen-cards-resource-patch") -@HideEndscreenCardsCompatibility -@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class HideEndscreenCardsResourcePatch : ResourcePatch { - internal companion object { - var layoutCircle: Long = -1 - var layoutIcon: Long = -1 - var layoutVideo: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_endscreen_cards", - StringResource("revanced_hide_endscreen_cards_title", "Hide end-screen cards"), - true, - StringResource("revanced_hide_endscreen_cards_summary_on", "End-screen cards are hidden"), - StringResource("revanced_hide_endscreen_cards_summary_off", "End-screen cards are shown") - ), - ) - - fun findEndscreenResourceId(name: String) = ResourceMappingPatch.resourceMappings.single { - it.type == "layout" && it.name == "endscreen_element_layout_$name" - }.id - - layoutCircle = findEndscreenResourceId("circle") - layoutIcon = findEndscreenResourceId("icon") - layoutVideo = findEndscreenResourceId("video") - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/annotations/HideInfocardsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/annotations/HideInfocardsCompatibility.kt deleted file mode 100644 index 03b2030db..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/annotations/HideInfocardsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.hideinfocards.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideInfocardsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsIncognitoFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsIncognitoFingerprint.kt deleted file mode 100644 index 03df9af88..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsIncognitoFingerprint.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.layout.hideinfocards.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object InfocardsIncognitoFingerprint : MethodFingerprint( - "Ljava/lang/Boolean;", - AccessFlags.PUBLIC or AccessFlags.FINAL, - strings = listOf("vibrator") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsMethodCallFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsMethodCallFingerprint.kt deleted file mode 100644 index 222a18e15..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsMethodCallFingerprint.kt +++ /dev/null @@ -1,19 +0,0 @@ -package app.revanced.patches.youtube.layout.hideinfocards.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hideinfocards.resource.patch.HideInfocardsResourcePatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object InfocardsMethodCallFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - ), - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { instruction -> - (instruction as? WideLiteralInstruction)?.wideLiteral == HideInfocardsResourcePatch.drawerResourceId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/patch/HideInfocardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/patch/HideInfocardsPatch.kt deleted file mode 100644 index 9d5f0409b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/patch/HideInfocardsPatch.kt +++ /dev/null @@ -1,77 +0,0 @@ -package app.revanced.patches.youtube.layout.hideinfocards.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.layout.hideinfocards.annotations.HideInfocardsCompatibility -import app.revanced.patches.youtube.layout.hideinfocards.fingerprints.InfocardsIncognitoFingerprint -import app.revanced.patches.youtube.layout.hideinfocards.fingerprints.InfocardsIncognitoParentFingerprint -import app.revanced.patches.youtube.layout.hideinfocards.fingerprints.InfocardsMethodCallFingerprint -import app.revanced.patches.youtube.layout.hideinfocards.resource.patch.HideInfocardsResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.builder.instruction.BuilderInstruction35c - -@Patch -@DependsOn([IntegrationsPatch::class, HideInfocardsResourcePatch::class]) -@Name("hide-info-cards") -@Description("Hides info-cards in videos.") -@HideInfocardsCompatibility -@Version("0.0.1") -class HideInfocardsPatch : BytecodePatch( - listOf( - InfocardsIncognitoParentFingerprint, - InfocardsMethodCallFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - with(InfocardsIncognitoFingerprint.also { - it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef) - }.result!!.mutableMethod) { - val invokeInstructionIndex = implementation!!.instructions.indexOfFirst { - it.opcode.ordinal == Opcode.INVOKE_VIRTUAL.ordinal && - ((it as? BuilderInstruction35c)?.reference.toString() == - "Landroid/view/View;->setVisibility(I)V") - } - - replaceInstruction( - invokeInstructionIndex, - "invoke-static {v${(instruction(invokeInstructionIndex) as? BuilderInstruction35c)?.registerC}}," + - " Lapp/revanced/integrations/patches/HideInfocardsPatch;->hideInfocardsIncognito(Landroid/view/View;)V" - ) - } - - with(InfocardsMethodCallFingerprint.result!!) { - val hideInfocardsCallMethod = mutableMethod - - val invokeInterfaceIndex = scanResult.patternScanResult!!.endIndex - val toggleRegister = hideInfocardsCallMethod.implementation!!.registerCount - 1 - - hideInfocardsCallMethod.addInstructions( - invokeInterfaceIndex, """ - invoke-static {}, Lapp/revanced/integrations/patches/HideInfocardsPatch;->hideInfocardsMethodCall()Z - move-result v$toggleRegister - if-nez v$toggleRegister, :hide_info_cards - """, - listOf( - ExternalLabel( - "hide_info_cards", hideInfocardsCallMethod.instruction(invokeInterfaceIndex + 1) - ) - ) - ) - } - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/resource/patch/HideInfocardsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/resource/patch/HideInfocardsResourcePatch.kt deleted file mode 100644 index ff58fb573..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/resource/patch/HideInfocardsResourcePatch.kt +++ /dev/null @@ -1,40 +0,0 @@ -package app.revanced.patches.youtube.layout.hideinfocards.resource.patch - -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.layout.hideinfocards.annotations.HideInfocardsCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@HideInfocardsCompatibility -@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class HideInfocardsResourcePatch : ResourcePatch { - internal companion object { - var drawerResourceId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_infocards", - StringResource("revanced_hide_infocards_title", "Hide info-cards"), - true, - StringResource("revanced_hide_infocards_summary_on", "Info-cards are hidden"), - StringResource("revanced_hide_infocards_summary_off", "Info-cards are shown") - ) - ) - - drawerResourceId = ResourceMappingPatch.resourceMappings.single { - it.type == "id" && it.name == "info_cards_drawer_header" - }.id - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/annotations/MixPlaylistsPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/annotations/MixPlaylistsPatchCompatibility.kt deleted file mode 100644 index 030bc1ea4..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/annotations/MixPlaylistsPatchCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.hidemixplaylists.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MixPlaylistsPatchCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/patch/MixPlaylistsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/patch/MixPlaylistsPatch.kt deleted file mode 100644 index e24184814..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidemixplaylists/patch/MixPlaylistsPatch.kt +++ /dev/null @@ -1,64 +0,0 @@ -package app.revanced.patches.youtube.layout.hidemixplaylists.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -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.BytecodePatch -import app.revanced.patches.youtube.layout.hidemixplaylists.annotations.MixPlaylistsPatchCompatibility -import app.revanced.patches.youtube.layout.hidemixplaylists.fingerprints.CreateMixPlaylistFingerprint -import app.revanced.patches.youtube.layout.hidemixplaylists.fingerprints.SecondCreateMixPlaylistFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class]) -@Name("hide-my-mix") -@Description("Hides mix playlists.") -@MixPlaylistsPatchCompatibility -@Version("0.0.1") -class MixPlaylistsPatch : BytecodePatch( - listOf( - CreateMixPlaylistFingerprint, SecondCreateMixPlaylistFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_mix_playlists", - StringResource("revanced_hide_mix_playlists_title", "Hide mix playlists"), - false, - StringResource("revanced_hide_mix_playlists_summary_on", "Mix playlists are hidden"), - StringResource("revanced_hide_mix_playlists_summary_off", "Mix playlists are shown") - ) - ) - - arrayOf(CreateMixPlaylistFingerprint, SecondCreateMixPlaylistFingerprint).forEach(::addHook) - - return PatchResultSuccess() - } - - private fun addHook(fingerprint: MethodFingerprint) { - with (fingerprint.result!!) { - val insertIndex = scanResult.patternScanResult!!.endIndex - 3 - - val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA - - mutableMethod.addInstruction( - insertIndex, - "invoke-static {v$register}, Lapp/revanced/integrations/patches/HideMixPlaylistsPatch;->hideMixPlaylists(Landroid/view/View;)V" - ) - } - - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/annotations/HideTimeAndSeekbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/annotations/HideTimeAndSeekbarCompatibility.kt deleted file mode 100644 index c6b4b2ab3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/annotations/HideTimeAndSeekbarCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.hidetimeandseekbar.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideTimeAndSeekbarCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/patch/HideTimeAndSeekbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/patch/HideTimeAndSeekbarPatch.kt deleted file mode 100644 index 8a7821ada..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/patch/HideTimeAndSeekbarPatch.kt +++ /dev/null @@ -1,76 +0,0 @@ -package app.revanced.patches.youtube.layout.hidetimeandseekbar.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.fingerprints.SeekbarFingerprint -import app.revanced.patches.shared.fingerprints.SeekbarOnDrawFingerprint -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.layout.hidetimeandseekbar.annotations.HideTimeAndSeekbarCompatibility -import app.revanced.patches.youtube.layout.hidetimeandseekbar.fingerprints.TimeCounterFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("hide-time-and-seekbar") -@Description("Hides progress bar and time counter on videos.") -@HideTimeAndSeekbarCompatibility -@Version("0.0.1") -class HideTimeAndSeekbarPatch : BytecodePatch( - listOf( - SeekbarFingerprint, TimeCounterFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_time_and_seekbar", - StringResource("revanced_hide_time_and_seekbar_title", "Hide time and seekbar"), - false, - StringResource("revanced_hide_time_and_seekbar_summary_on", "Time and seekbar are hidden"), - StringResource("revanced_hide_time_and_seekbar_summary_off", "Time and seekbar are shown") - ) - ) - - val createVideoPlayerSeekbarMethod = SeekbarFingerprint.result!!.let { - SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) } - }.result!!.mutableMethod - - createVideoPlayerSeekbarMethod.addInstructions( - 0, """ - const/4 v0, 0x0 - invoke-static { }, Lapp/revanced/integrations/patches/HideTimeAndSeekbarPatch;->hideTimeAndSeekbar()Z - move-result v0 - if-eqz v0, :hide_time_and_seekbar - return-void - :hide_time_and_seekbar - nop - """ - ) - - val timeCounterMethod = TimeCounterFingerprint.result!!.mutableMethod - - timeCounterMethod.addInstructions( - 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/HideTimeAndSeekbarPatch;->hideTimeAndSeekbar()Z - move-result v0 - if-eqz v0, :hide_time_and_seekbar - return-void - :hide_time_and_seekbar - nop - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt deleted file mode 100644 index e6e5058e2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/annotations/OldQualityLayoutCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.oldqualitylayout.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class OldQualityLayoutCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt deleted file mode 100644 index 4abb688e9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/fingerprints/QualityMenuViewInflateFingerprint.kt +++ /dev/null @@ -1,31 +0,0 @@ -package app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object QualityMenuViewInflateFingerprint : MethodFingerprint( - "L", AccessFlags.FINAL or AccessFlags.PUBLIC, listOf("L", "L", "L"), listOf( - Opcode.INVOKE_SUPER, - Opcode.CONST, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.CONST_STRING, - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt deleted file mode 100644 index dd4597b01..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/oldqualitylayout/patch/OldQualityLayoutPatch.kt +++ /dev/null @@ -1,61 +0,0 @@ -package app.revanced.patches.youtube.layout.oldqualitylayout.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.oldqualitylayout.annotations.OldQualityLayoutCompatibility -import app.revanced.patches.youtube.layout.oldqualitylayout.fingerprints.QualityMenuViewInflateFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("old-quality-layout") -@Description("Enables the original video quality flyout in the video player settings") -@OldQualityLayoutCompatibility -@Version("0.0.1") -// new ReVanced users have no idea what it means to use the "old quality layout menu" -// maybe rename this patch to better describe what it provides (ie: user-selectable-video-resolution ) -class OldQualityLayoutPatch : BytecodePatch( - listOf(QualityMenuViewInflateFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_use_old_style_quality_settings", - StringResource("revanced_old_style_quality_settings_enabled_title", "Use old video quality player menu"), - true, - StringResource("revanced_old_style_quality_settings_summary_on", "Old video quality menu is used"), - StringResource("revanced_old_style_quality_settings_summary_off", "Old video quality menu is not used") - ) - ) - - val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!! - val method = inflateFingerprintResult.mutableMethod - val instructions = method.implementation!!.instructions - - // at this index the listener is added to the list view - val listenerInvokeRegister = instructions.size - 1 - 1 - - // get the register which stores the quality menu list view - val onItemClickViewRegister = (instructions[listenerInvokeRegister] as FiveRegisterInstruction).registerC - - // insert the integrations method - method.addInstruction( - listenerInvokeRegister, // insert the integrations instructions right before the listener - "invoke-static { v$onItemClickViewRegister }, Lapp/revanced/integrations/patches/playback/quality/OldQualityLayoutPatch;->showOldQualityMenu(Landroid/widget/ListView;)V" - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/annotations/HideEmailAddressCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/annotations/HideEmailAddressCompatibility.kt deleted file mode 100644 index 527d1b842..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/annotations/HideEmailAddressCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.personalinformation.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideEmailAddressCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt deleted file mode 100644 index 4029b8313..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/personalinformation/resource/patch/HideEmailAddressResourcePatch.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.youtube.layout.personalinformation.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.layout.personalinformation.annotations.HideEmailAddressCompatibility -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Name("hide-email-address-resource-patch") -@HideEmailAddressCompatibility -@DependsOn([SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class HideEmailAddressResourcePatch : ResourcePatch { - companion object { - internal var accountSwitcherAccessibilityLabelId: Long = -1 - } - - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_email_address", - StringResource("revanced_hide_email_address_title", "Hide email in account switcher"), - false, - StringResource("revanced_hide_email_address_summary_on", "Email address is hidden"), - StringResource("revanced_hide_email_address_summary_off", "Email address is shown") - ) - ) - - accountSwitcherAccessibilityLabelId = ResourceMappingPatch.resourceMappings.single { - it.type == "string" && it.name == "account_switcher_accessibility_label" - }.id - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/annotations/PivotBarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/annotations/PivotBarCompatibility.kt deleted file mode 100644 index 145706251..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/annotations/PivotBarCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.pivotbar.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PivotBarCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt deleted file mode 100644 index f3b70d54a..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/createbutton/patch/CreateButtonRemoverPatch.kt +++ /dev/null @@ -1,71 +0,0 @@ -package app.revanced.patches.youtube.layout.pivotbar.createbutton.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.layout.pivotbar.annotations.PivotBarCompatibility -import app.revanced.patches.youtube.layout.pivotbar.createbutton.fingerprints.PivotBarCreateButtonViewFingerprint -import app.revanced.patches.youtube.layout.pivotbar.fingerprints.InitializeButtonsFingerprint -import app.revanced.patches.youtube.layout.pivotbar.resource.patch.ResolvePivotBarFingerprintsPatch -import app.revanced.patches.youtube.layout.pivotbar.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT -import app.revanced.patches.youtube.layout.pivotbar.utils.InjectionUtils.injectHook -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, ResourceMappingPatch::class, SettingsPatch::class, ResolvePivotBarFingerprintsPatch::class]) -@Name("hide-create-button") -@Description("Hides the create button in the navigation bar.") -@PivotBarCompatibility -@Version("0.0.1") -class CreateButtonRemoverPatch : BytecodePatch() { - private companion object { - const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/HideCreateButtonPatch;" - } - - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_create_button", - StringResource("revanced_hide_create_button_title", "Hide create button"), - true, - StringResource("revanced_hide_create_button_summary_on", "Create button is hidden"), - StringResource("revanced_hide_create_button_summary_off", "Create button is shown") - ) - ) - - /* - * Resolve fingerprints - */ - - InitializeButtonsFingerprint.result!!.let { - if (!PivotBarCreateButtonViewFingerprint.resolve(context, it.mutableMethod, it.mutableClass)) - return PivotBarCreateButtonViewFingerprint.toErrorResult() - } - - val createButtonResult = PivotBarCreateButtonViewFingerprint.result!! - val insertIndex = createButtonResult.scanResult.patternScanResult!!.endIndex - - /* - * Inject hooks - */ - - val hook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->hideCreateButton(Landroid/view/View;)V" - - createButtonResult.mutableMethod.injectHook(hook, insertIndex) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/fingerprints/InitializeButtonsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/fingerprints/InitializeButtonsFingerprint.kt deleted file mode 100644 index 32a77f7b4..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/fingerprints/InitializeButtonsFingerprint.kt +++ /dev/null @@ -1,15 +0,0 @@ -package app.revanced.patches.youtube.layout.pivotbar.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.pivotbar.resource.patch.ResolvePivotBarFingerprintsPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - -object InitializeButtonsFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { - it.opcode == Opcode.CONST && (it as WideLiteralInstruction).wideLiteral == - ResolvePivotBarFingerprintsPatch.imageOnlyTabResourceId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/fingerprints/PivotBarConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/fingerprints/PivotBarConstructorFingerprint.kt deleted file mode 100644 index 0609dd1f4..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/fingerprints/PivotBarConstructorFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.youtube.layout.pivotbar.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object PivotBarConstructorFingerprint : MethodFingerprint( - access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - strings = listOf("com.google.android.apps.youtube.app.endpoint.flags") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/resource/patch/ResolvePivotBarFingerprintsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/resource/patch/ResolvePivotBarFingerprintsPatch.kt deleted file mode 100644 index 785d61c53..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/resource/patch/ResolvePivotBarFingerprintsPatch.kt +++ /dev/null @@ -1,45 +0,0 @@ -package app.revanced.patches.youtube.layout.pivotbar.resource.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.layout.pivotbar.annotations.PivotBarCompatibility -import app.revanced.patches.youtube.layout.pivotbar.fingerprints.InitializeButtonsFingerprint -import app.revanced.patches.youtube.layout.pivotbar.fingerprints.PivotBarConstructorFingerprint - -@DependsOn([ResourceMappingPatch::class]) -@PivotBarCompatibility -@Description("Resolves necessary fingerprints.") -@Version("0.0.1") -class ResolvePivotBarFingerprintsPatch : BytecodePatch( - listOf(PivotBarConstructorFingerprint) -) { - internal companion object { - var imageOnlyTabResourceId: Long = -1 - } - - override fun execute(context: BytecodeContext): PatchResult { - // imageOnlyTabResourceId is used in InitializeButtonsFingerprint fingerprint - ResourceMappingPatch.resourceMappings.find { it.type == "layout" && it.name == "image_only_tab" } - ?.let { imageOnlyTabResourceId = it.id } ?: return PatchResultError("Failed to find resource") - - PivotBarConstructorFingerprint.result?.let { - // Resolve InitializeButtonsFingerprint on the class of the method - // which PivotBarConstructorFingerprint resolved to - if (!InitializeButtonsFingerprint.resolve( - context, - it.classDef - ) - ) return InitializeButtonsFingerprint.toErrorResult() - } ?: return PivotBarConstructorFingerprint.toErrorResult() - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/patch/ShortsButtonRemoverPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/patch/ShortsButtonRemoverPatch.kt deleted file mode 100644 index 259f1bcec..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/shortsbutton/patch/ShortsButtonRemoverPatch.kt +++ /dev/null @@ -1,93 +0,0 @@ -package app.revanced.patches.youtube.layout.pivotbar.shortsbutton.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.layout.pivotbar.annotations.PivotBarCompatibility -import app.revanced.patches.youtube.layout.pivotbar.fingerprints.InitializeButtonsFingerprint -import app.revanced.patches.youtube.layout.pivotbar.resource.patch.ResolvePivotBarFingerprintsPatch -import app.revanced.patches.youtube.layout.pivotbar.shortsbutton.fingerprints.PivotBarEnumFingerprint -import app.revanced.patches.youtube.layout.pivotbar.shortsbutton.fingerprints.PivotBarShortsButtonViewFingerprint -import app.revanced.patches.youtube.layout.pivotbar.utils.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT -import app.revanced.patches.youtube.layout.pivotbar.utils.InjectionUtils.injectHook -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class, ResolvePivotBarFingerprintsPatch::class]) -@Name("hide-shorts-button") -@Description("Hides the shorts button on the navigation bar.") -@PivotBarCompatibility -@Version("0.0.1") -class ShortsButtonRemoverPatch : BytecodePatch() { - private companion object { - const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/HideShortsButtonPatch;" - } - - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_shorts_button", - StringResource("revanced_hide_shorts_button_title", "Hide shorts button"), - true, - StringResource("revanced_hide_shorts_button_summary_on", "Shorts button is hidden"), - StringResource("revanced_hide_shorts_button_summary_off", "Shorts button is shown") - ) - ) - - /* - * Resolve fingerprints - */ - - val initializeButtonsResult = InitializeButtonsFingerprint.result!! - - val fingerprintResults = - arrayOf(PivotBarEnumFingerprint, PivotBarShortsButtonViewFingerprint) - .onEach { - if (!it.resolve( - context, - initializeButtonsResult.mutableMethod, - initializeButtonsResult.mutableClass - ) - ) - return it.toErrorResult() - } - .map { it.result!!.scanResult.patternScanResult!! } - - - val enumScanResult = fingerprintResults[0] - val buttonViewResult = fingerprintResults[1] - - val enumHookInsertIndex = enumScanResult.startIndex + 2 - val buttonHookInsertIndex = buttonViewResult.endIndex - - /* - * Inject hooks - */ - - val enumHook = "sput-object v$REGISTER_TEMPLATE_REPLACEMENT, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->lastPivotTab:Ljava/lang/Enum;" - val buttonHook = "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, " + - "$INTEGRATIONS_CLASS_DESCRIPTOR->hideShortsButton(Landroid/view/View;)V" - - // Inject bottom to top to not mess up the indices - mapOf( - buttonHook to buttonHookInsertIndex, - enumHook to enumHookInsertIndex - ).forEach { (hook, insertIndex) -> - initializeButtonsResult.mutableMethod.injectHook(hook, insertIndex) - } - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/bytecode/fingerprints/LayoutConstructorFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/bytecode/fingerprints/LayoutConstructorFingerprint.kt index fcc47c134..6596b7147 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autoplaybutton/fingerprints/LayoutConstructorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/bytecode/fingerprints/LayoutConstructorFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.autoplaybutton.fingerprints +package app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/bytecode/patch/HideAutoplayButtonBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/bytecode/patch/HideAutoplayButtonBytecodePatch.kt new file mode 100644 index 000000000..f99648355 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/bytecode/patch/HideAutoplayButtonBytecodePatch.kt @@ -0,0 +1,61 @@ +package app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.fingerprints.LayoutConstructorFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT +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 + +@Name("hide-autoplay-button-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class HideAutoplayButtonBytecodePatch : BytecodePatch( + listOf( + LayoutConstructorFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val layoutGenMethodResult = LayoutConstructorFingerprint.result!! + val layoutGenMethod = layoutGenMethodResult.mutableMethod + val layoutGenMethodInstructions = layoutGenMethod.implementation!!.instructions + + // resolve the offsets such as ... + val autoNavPreviewStubId = ResourceMappingPatch.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 {}, $PLAYER_LAYOUT->hideAutoPlayButton()Z + move-result v15 + if-nez v15, :hidden + """, listOf(ExternalLabel("hidden", jumpInstruction)) + ) + + return PatchResultSuccess() + } +} + diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/resource/patch/HideAutoplayButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/resource/patch/HideAutoplayButtonPatch.kt new file mode 100644 index 000000000..8a755e2ba --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/autoplaybutton/resource/patch/HideAutoplayButtonPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.autoplaybutton.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.patch.HideAutoplayButtonBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-autoplay-button") +@Description("Hides the autoplay button in the video player.") +@DependsOn( + [ + HideAutoplayButtonBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideAutoplayButtonPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_AUTOPLAY_BUTTON" + ) + + ResourceHelper.patchSuccess( + context, + "hide-autoplay-button" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/captionsbutton/bytecode/patch/HideCaptionsButtonBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/captionsbutton/bytecode/patch/HideCaptionsButtonBytecodePatch.kt new file mode 100644 index 000000000..28c2c339d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/captionsbutton/bytecode/patch/HideCaptionsButtonBytecodePatch.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.youtube.layout.player.captionsbutton.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint +import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT +import org.jf.dexlib2.Opcode + +@Name("hide-captions-button-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideCaptionsButtonBytecodePatch : BytecodePatch(listOf( + SubtitleButtonControllerFingerprint, +)) { + override fun execute(context: BytecodeContext): PatchResult { + + val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod + val subtitleButtonControllerMethodInstructions = subtitleButtonControllerMethod.implementation!!.instructions + + for ((index, instruction) in subtitleButtonControllerMethodInstructions.withIndex()) { + if (instruction.opcode != Opcode.IGET_BOOLEAN) continue + + subtitleButtonControllerMethod.addInstruction( + index + 1, + "invoke-static {v0}, $PLAYER_LAYOUT->hideCaptionsButton(Landroid/widget/ImageView;)V" + ) + + break + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/captionsbutton/resource/patch/HideCaptionsButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/captionsbutton/resource/patch/HideCaptionsButtonPatch.kt new file mode 100644 index 000000000..94c705a76 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/captionsbutton/resource/patch/HideCaptionsButtonPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.captionsbutton.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.captionsbutton.bytecode.patch.HideCaptionsButtonBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-player-captions-button") +@Description("Hides the captions button in the video player.") +@DependsOn( + [ + HideCaptionsButtonBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideCaptionsButtonPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_CAPTIONS_BUTTON" + ) + + ResourceHelper.patchSuccess( + context, + "hide-captions-button" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/castbutton/bytecode/patch/HideCastButtonBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/castbutton/bytecode/patch/HideCastButtonBytecodePatch.kt new file mode 100644 index 000000000..439e2b6fb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/castbutton/bytecode/patch/HideCastButtonBytecodePatch.kt @@ -0,0 +1,36 @@ +package app.revanced.patches.youtube.layout.player.castbutton.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT + +@Name("hide-cast-button-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideCastButtonBytecodePatch : BytecodePatch() { + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + if (classDef.type.endsWith("MediaRouteButton;") && method.name == "setVisibility") { + val setVisibilityMethod = + context.proxy(classDef).mutableClass.methods.first { it.name == "setVisibility" } + + setVisibilityMethod.addInstructions( + 0, """ + invoke-static {p1}, $PLAYER_LAYOUT->hideCastButton(I)I + move-result p1 + """ + ) + } + } + } + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/castbutton/resource/patch/HideCastButtonPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/castbutton/resource/patch/HideCastButtonPatch.kt new file mode 100644 index 000000000..608115fee --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/castbutton/resource/patch/HideCastButtonPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.castbutton.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.castbutton.bytecode.patch.HideCastButtonBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-cast-button") +@Description("Hides the cast button in the video player.") +@DependsOn( + [ + HideCastButtonBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideCastButtonPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_CAST_BUTTON" + ) + + ResourceHelper.patchSuccess( + context, + "hide-cast-button" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt similarity index 66% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt index 505345f67..f1c52d273 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidealbumcards/bytecode/fingerprints/AlbumCardsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt @@ -1,13 +1,12 @@ -package app.revanced.patches.youtube.layout.hidealbumcards.bytecode.fingerprints +package app.revanced.patches.youtube.layout.player.endscreencards.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hidealbumcards.resource.patch.AlbumCardsResourcePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode -object AlbumCardsFingerprint : MethodFingerprint( +object LayoutCircleFingerprint : MethodFingerprint( opcodes = listOf( - Opcode.MOVE_RESULT_OBJECT, Opcode.CONST, Opcode.CONST_4, Opcode.INVOKE_VIRTUAL, @@ -17,7 +16,7 @@ object AlbumCardsFingerprint : MethodFingerprint( customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == AlbumCardsResourcePatch.albumCardId + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.layoutCircle } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt similarity index 64% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt index 8e5730bfd..453e2e92d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutIconFingerprint.kt @@ -1,9 +1,9 @@ -package app.revanced.patches.youtube.layout.hideendscreencards.bytecode.fingerprints +package app.revanced.patches.youtube.layout.player.endscreencards.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hideendscreencards.resource.patch.HideEndscreenCardsResourcePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode object LayoutIconFingerprint : MethodFingerprint( opcodes = listOf( @@ -16,7 +16,7 @@ object LayoutIconFingerprint : MethodFingerprint( customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == HideEndscreenCardsResourcePatch.layoutIcon + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.layoutIcon } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt similarity index 64% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt index 4d91d2902..9e63c822d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/fingerprints/LayoutVideoFingerprint.kt @@ -1,9 +1,9 @@ -package app.revanced.patches.youtube.layout.hideendscreencards.bytecode.fingerprints +package app.revanced.patches.youtube.layout.player.endscreencards.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hideendscreencards.resource.patch.HideEndscreenCardsResourcePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode object LayoutVideoFingerprint : MethodFingerprint( opcodes = listOf( @@ -16,7 +16,7 @@ object LayoutVideoFingerprint : MethodFingerprint( customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == HideEndscreenCardsResourcePatch.layoutVideo + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.layoutVideo } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/patch/HideEndscreenCardsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/patch/HideEndscreenCardsBytecodePatch.kt new file mode 100644 index 000000000..4233a2115 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/bytecode/patch/HideEndscreenCardsBytecodePatch.kt @@ -0,0 +1,46 @@ +package app.revanced.patches.youtube.layout.player.endscreencards.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.Fingerprint +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.layout.player.endscreencards.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.injectHideCall +import org.jf.dexlib2.iface.instruction.formats.Instruction21c + +@Name("hide-endscreen-cards-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideEndscreenCardsBytecodePatch : BytecodePatch( + listOf( + LayoutCircleFingerprint, + LayoutIconFingerprint, + LayoutVideoFingerprint, + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + fun MethodFingerprint.injectHideCalls() { + val layoutResult = result!! + val layoutMethod = layoutResult.mutableMethod + + val checkCastIndex = layoutResult.scanResult.patternScanResult!!.endIndex + val viewRegister = (layoutMethod.instruction(checkCastIndex) as Instruction21c).registerA + + layoutMethod.implementation!!.injectHideCall(checkCastIndex + 1, viewRegister, "layout/PlayerLayoutPatch", "hideEndscreen") + } + + listOf(LayoutCircleFingerprint, LayoutIconFingerprint, LayoutVideoFingerprint).forEach(MethodFingerprint::injectHideCalls) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/resource/patch/HideEndscreenCardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/resource/patch/HideEndscreenCardsPatch.kt new file mode 100644 index 000000000..5454cc709 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/endscreencards/resource/patch/HideEndscreenCardsPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.endscreencards.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.endscreencards.bytecode.patch.HideEndscreenCardsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-endscreen-cards") +@Description("Hides the suggested video cards at the end of a video in fullscreen.") +@DependsOn( + [ + HideEndscreenCardsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideEndscreenCardsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_ENDSCREEN_CARDS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-endscreen-cards" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/fingerprints/InfocardsIncognitoFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/fingerprints/InfocardsIncognitoFingerprint.kt new file mode 100644 index 000000000..bf368fede --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/fingerprints/InfocardsIncognitoFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.layout.player.infocards.bytecode.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.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("infocards-incognito-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") +object InfocardsIncognitoFingerprint : MethodFingerprint( + "Ljava/lang/Boolean;", + AccessFlags.PUBLIC or AccessFlags.FINAL, + strings = listOf("vibrator") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsIncognitoParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/fingerprints/InfocardsIncognitoParentFingerprint.kt similarity index 51% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsIncognitoParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/fingerprints/InfocardsIncognitoParentFingerprint.kt index 53a6be465..e49c66a34 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideinfocards/fingerprints/InfocardsIncognitoParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/fingerprints/InfocardsIncognitoParentFingerprint.kt @@ -1,9 +1,15 @@ -package app.revanced.patches.youtube.layout.hideinfocards.fingerprints +package app.revanced.patches.youtube.layout.player.infocards.bytecode.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.shared.annotation.YouTubeCompatibility import org.jf.dexlib2.AccessFlags +@Name("infocards-incognito-parent-fingerprint") +@YouTubeCompatibility +@Version("0.0.1") object InfocardsIncognitoParentFingerprint : MethodFingerprint( "Ljava/lang/String;", AccessFlags.PUBLIC or AccessFlags.FINAL, diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/patch/HideInfoCardsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/patch/HideInfoCardsBytecodePatch.kt new file mode 100644 index 000000000..cdc5518ac --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/bytecode/patch/HideInfoCardsBytecodePatch.kt @@ -0,0 +1,39 @@ +package app.revanced.patches.youtube.layout.player.infocards.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoFingerprint +import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoParentFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT +import org.jf.dexlib2.builder.instruction.BuilderInstruction35c +import org.jf.dexlib2.Opcode + +@Name("hide-info-cards-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideInfoCardsBytecodePatch : BytecodePatch( + listOf(InfocardsIncognitoParentFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + with(InfocardsIncognitoFingerprint.also { + it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef) + }.result!!.mutableMethod) { + addInstructions( + 1, """ + invoke-static {v0}, $PLAYER_LAYOUT->hideInfoCard(Z)Z + move-result v0 + """ + ) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/resource/patch/HideInfocardsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/resource/patch/HideInfocardsPatch.kt new file mode 100644 index 000000000..bef61b4d4 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/infocards/resource/patch/HideInfocardsPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.infocards.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.infocards.bytecode.patch.HideInfoCardsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-info-cards") +@Description("Hides info-cards in videos.") +@DependsOn( + [ + HideInfoCardsBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideInfoCardsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_INFO_CARDS" + ) + + ResourceHelper.patchSuccess( + context, + "hide-info-cards" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/playeroverlayfilter/bytecode/patch/PlayerOverlayFilterBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/playeroverlayfilter/bytecode/patch/PlayerOverlayFilterBytecodePatch.kt new file mode 100644 index 000000000..edf2d1cb1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/playeroverlayfilter/bytecode/patch/PlayerOverlayFilterBytecodePatch.kt @@ -0,0 +1,75 @@ +package app.revanced.patches.youtube.layout.player.playeroverlayfilter.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.iface.instruction.formats.Instruction21c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@DependsOn([ResourceMappingPatch::class]) +@Name("hide-player-overlay-filter-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class PlayerOverlayFilterBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "scrim_overlay", + "google_transparent" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // player overlay filter + val insertIndex = index + 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA + val viewRegister = (invokeInstruction as Instruction21c).registerA + + val transparent = resourceIds[1] + + mutableMethod.addInstructions( + insertIndex + 1, """ + invoke-static {}, Lapp/revanced/integrations/patches/layout/PlayerLayoutPatch;->hidePlayerOverlayFilter()Z + move-result v$dummyRegister + if-eqz v$dummyRegister, :currentcolor + const v$dummyRegister, $transparent + invoke-virtual {v$viewRegister, v$dummyRegister}, Landroid/widget/ImageView;->setImageResource(I)V + """, listOf(ExternalLabel("currentcolor", mutableMethod.instruction(insertIndex + 1))) + ) + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/playeroverlayfilter/resource/patch/PlayerOverlayFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/playeroverlayfilter/resource/patch/PlayerOverlayFilterPatch.kt new file mode 100644 index 000000000..3871b60f6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/playeroverlayfilter/resource/patch/PlayerOverlayFilterPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.playeroverlayfilter.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.playeroverlayfilter.bytecode.patch.PlayerOverlayFilterBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-player-overlay-filter") +@Description("Hide the suggested actions bar inside the player.") +@DependsOn( + [ + SettingsPatch::class, + PlayerOverlayFilterBytecodePatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class PlayerOverlayFilterPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_PALYER_OVERLAY_FILTER" + ) + + ResourceHelper.patchSuccess( + context, + "hide-player-overlay-filter" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/suggestactions/bytecode/patch/SuggestedActionsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/suggestactions/bytecode/patch/SuggestedActionsBytecodePatch.kt new file mode 100644 index 000000000..e35136498 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/suggestactions/bytecode/patch/SuggestedActionsBytecodePatch.kt @@ -0,0 +1,63 @@ +package app.revanced.patches.youtube.layout.player.suggestactions.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectHideCall +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@DependsOn([ResourceMappingPatch::class]) +@Name("hide-suggested-actions-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class SuggestedActionsBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "suggested_action" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // suggested_action + val insertIndex = index + 4 + val iPutInstruction = instructions.elementAt(insertIndex) + if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (iPutInstruction as Instruction22c).registerA + mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/PlayerLayoutPatch", "hideSuggestedActions") + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/suggestactions/resource/patch/SuggestedActionsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/suggestactions/resource/patch/SuggestedActionsPatch.kt new file mode 100644 index 000000000..78b85573f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/suggestactions/resource/patch/SuggestedActionsPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.suggestactions.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.suggestactions.bytecode.patch.SuggestedActionsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-suggested-actions") +@Description("Hide the suggested actions bar inside the player.") +@DependsOn( + [ + SettingsPatch::class, + SuggestedActionsBytecodePatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SuggestedActionsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_SUGGESTED_ACTION" + ) + + ResourceHelper.patchSuccess( + context, + "hide-suggested-actions" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/fingerprints/HideWatermarkFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/fingerprints/HideWatermarkFingerprint.kt similarity index 55% rename from src/main/kotlin/app/revanced/patches/youtube/layout/watermark/fingerprints/HideWatermarkFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/fingerprints/HideWatermarkFingerprint.kt index 088edb70f..dad95c3ab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/fingerprints/HideWatermarkFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/fingerprints/HideWatermarkFingerprint.kt @@ -1,9 +1,11 @@ -package app.revanced.patches.youtube.layout.watermark.fingerprints +package app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags +@FuzzyPatternScanMethod(3) object HideWatermarkFingerprint : MethodFingerprint ( - "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L") + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L"), null ,null, null ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/fingerprints/HideWatermarkParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/fingerprints/HideWatermarkParentFingerprint.kt new file mode 100644 index 000000000..81b695eae --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/fingerprints/HideWatermarkParentFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +@FuzzyPatternScanMethod(3) +object HideWatermarkParentFingerprint : MethodFingerprint ( + "L", AccessFlags.PUBLIC or AccessFlags.FINAL, null, null, listOf("player_overlay_in_video_programming"), null +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/patch/HideChannelWatermarkBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/patch/HideChannelWatermarkBytecodePatch.kt new file mode 100644 index 000000000..a51b35604 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/bytecode/patch/HideChannelWatermarkBytecodePatch.kt @@ -0,0 +1,44 @@ +package app.revanced.patches.youtube.layout.player.watermark.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.removeInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints.HideWatermarkFingerprint +import app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints.HideWatermarkParentFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT + +@Name("hide-channel-watermark-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideChannelWatermarkBytecodePatch : BytecodePatch( + listOf( + HideWatermarkParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + HideWatermarkFingerprint.resolve(context, HideWatermarkParentFingerprint.result!!.classDef) + val result = HideWatermarkFingerprint.result + ?: return PatchResultError("Required parent method could not be found.") + + val method = result.mutableMethod + val line = method.implementation!!.instructions.size - 5 + + method.removeInstruction(line) + method.addInstructions( + line, """ + invoke-static {}, $PLAYER_LAYOUT->hideChannelWatermark()Z + move-result p2 + """ + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/resource/patch/HideChannelWatermarkPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/resource/patch/HideChannelWatermarkPatch.kt new file mode 100644 index 000000000..3cb52f45b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/player/watermark/resource/patch/HideChannelWatermarkPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.player.watermark.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.player.watermark.bytecode.patch.HideChannelWatermarkBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-channel-watermark") +@Description("Hides creator's watermarks on videos.") +@DependsOn( + [ + HideChannelWatermarkBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideChannelWatermarkPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: PLAYER", + "SETTINGS: HIDE_CHANNEL_WATERMARK" + ) + + ResourceHelper.patchSuccess( + context, + "hide-channel-watermark" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerbuttonbackground/annotations/PlayerButtonBackgroundCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerbuttonbackground/annotations/PlayerButtonBackgroundCompatibility.kt deleted file mode 100644 index 016ff8f05..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerbuttonbackground/annotations/PlayerButtonBackgroundCompatibility.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.youtube.layout.playerbuttonbackground.annotations -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.google.android.youtube", arrayOf("17.49.37")) - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PlayerButtonBackgroundCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerbuttonbackground/patch/PlayerButtonBackgroundPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerbuttonbackground/patch/PlayerButtonBackgroundPatch.kt deleted file mode 100644 index c99615d93..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerbuttonbackground/patch/PlayerButtonBackgroundPatch.kt +++ /dev/null @@ -1,41 +0,0 @@ -package app.revanced.patches.youtube.layout.playerbuttonbackground.patch - -import app.revanced.extensions.doRecursively -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patches.youtube.layout.playerbuttonbackground.annotations.PlayerButtonBackgroundCompatibility -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import org.w3c.dom.Element - -@Patch -@DependsOn([FixLocaleConfigErrorPatch::class]) -@Name("remove-player-button-background") -@Description("Removes the background from the video player buttons.") -@PlayerButtonBackgroundCompatibility -@Version("0.0.1") -class PlayerButtonBackgroundPatch : ResourcePatch { - private companion object { - const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml" - } - - override fun execute(context: ResourceContext): PatchResult { - context.xmlEditor[RESOURCE_FILE_PATH].use { editor -> - editor.file.doRecursively node@{ node -> - if (node !is Element) return@node - - node.getAttributeNode("android:color")?.let { attribute -> - attribute.textContent = "@android:color/transparent" - } - } - } - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/annotations/PlayerPopupPanelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/annotations/PlayerPopupPanelsCompatibility.kt deleted file mode 100644 index aad154cb4..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/annotations/PlayerPopupPanelsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.playerpopuppanels.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PlayerPopupPanelsCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt deleted file mode 100644 index 4b9636f56..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/fingerprints/EngagementPanelControllerFingerprint.kt +++ /dev/null @@ -1,36 +0,0 @@ -package app.revanced.patches.youtube.layout.playerpopuppanels.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - - -@FuzzyPatternScanMethod(3) -object EngagementPanelControllerFingerprint : MethodFingerprint( - "L", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("L", "L", "Z", "Z", "Z"), listOf( - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_FROM16, - Opcode.IGET_BOOLEAN, - Opcode.CONST_4, - Opcode.IF_NEZ, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.SGET_OBJECT, - Opcode.SGET_OBJECT, - Opcode.CONST_STRING, - Opcode.INVOKE_STATIC, - Opcode.RETURN_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - Opcode.CONST_4, - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt deleted file mode 100644 index 9aca33f4f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/playerpopuppanels/patch/PlayerPopupPanelsPatch.kt +++ /dev/null @@ -1,59 +0,0 @@ -package app.revanced.patches.youtube.layout.playerpopuppanels.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.playerpopuppanels.annotations.PlayerPopupPanelsCompatibility -import app.revanced.patches.youtube.layout.playerpopuppanels.fingerprints.EngagementPanelControllerFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("disable-auto-player-popup-panels") -@Description("Disable automatic popup panels (playlist or live chat) on video player.") -@PlayerPopupPanelsCompatibility -@Version("0.0.1") -class PlayerPopupPanelsPatch : BytecodePatch( - listOf( - EngagementPanelControllerFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_player_popup_panels_enabled", - StringResource("revanced_player_popup_panels_title", "Disable player popup panels"), - false, - StringResource("revanced_player_popup_panels_summary_on", "Player popup panels are disabled"), - StringResource("revanced_player_popup_panels_summary_off", "Player popup panels are enabled") - ) - ) - - val engagementPanelControllerMethod = EngagementPanelControllerFingerprint.result!!.mutableMethod - - engagementPanelControllerMethod.addInstructions( - 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/DisablePlayerPopupPanelsPatch;->disablePlayerPopupPanels()Z - move-result v0 - if-eqz v0, :player_popup_panels - if-eqz p4, :player_popup_panels - const/4 v0, 0x0 - return-object v0 - :player_popup_panels - nop - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/annotations/HideReelsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/reels/annotations/HideReelsCompatibility.kt deleted file mode 100644 index 280d5c184..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/annotations/HideReelsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.reels.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideReelsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/fingerprints/HideReelsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/reels/fingerprints/HideReelsFingerprint.kt deleted file mode 100644 index af24744e5..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/fingerprints/HideReelsFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.youtube.layout.reels.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object HideReelsFingerprint : MethodFingerprint( - access = AccessFlags.PROTECTED or AccessFlags.FINAL, parameters = listOf("L", "L"), - strings = listOf("multiReelDismissalCallback", "reelItemRenderers", "reelDismissalInfo") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt deleted file mode 100644 index 65ed14c9c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/reels/patch/HideReelsPatch.kt +++ /dev/null @@ -1,51 +0,0 @@ -package app.revanced.patches.youtube.layout.reels.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.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( - listOf( - HideReelsFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_reel_button", - StringResource("revanced_hide_reel_button_title", "Hide reels button"), - true, - StringResource("revanced_hide_reel_button_summary_on", "Reels button is hidden"), - StringResource("revanced_hide_reel_button_summary_off", "Reels button is shown") - ) - ) - - val result = HideReelsFingerprint.result!! - - // HideReel will hide the reel view before it is being used, - // so we pass the view to the HideReel method - result.mutableMethod.addInstruction( - result.scanResult.patternScanResult!!.endIndex, - "invoke-static { v2 }, Lapp/revanced/integrations/patches/HideReelsPatch;->HideReel(Landroid/view/View;)V" - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt deleted file mode 100644 index 393f8ed05..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/annotations/ReturnYouTubeDislikeCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ReturnYouTubeDislikeCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentFingerprint.kt deleted file mode 100644 index dadd8e607..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object TextComponentFingerprint : MethodFingerprint( - strings = listOf("com.google.android.apps.youtube.music") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentSpecParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentSpecParentFingerprint.kt deleted file mode 100644 index 631ca5f77..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/TextComponentSpecParentFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object TextComponentSpecParentFingerprint : MethodFingerprint( - strings = listOf("TextComponentSpec: No converter for extension: ") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt deleted file mode 100644 index de92cf149..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/patch/ReturnYouTubeDislikePatch.kt +++ /dev/null @@ -1,85 +0,0 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.MethodFingerprintExtensions.name -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.returnyoutubedislike.annotations.ReturnYouTubeDislikeCompatibility -import app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints.* -import app.revanced.patches.youtube.layout.returnyoutubedislike.resource.patch.ReturnYouTubeDislikeResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch - -@Patch -@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 -@Version("0.0.1") -class ReturnYouTubeDislikePatch : BytecodePatch( - listOf( - TextComponentSpecParentFingerprint, LikeFingerprint, DislikeFingerprint, RemoveLikeFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - listOf( - LikeFingerprint.toPatch(Vote.LIKE), - DislikeFingerprint.toPatch(Vote.DISLIKE), - RemoveLikeFingerprint.toPatch(Vote.REMOVE_LIKE) - ).forEach { (fingerprint, vote) -> - with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) { - mutableMethod.addInstructions( - 0, - """ - const/4 v0, ${vote.value} - invoke-static {v0}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;->sendVote(I)V - """ - ) - } - } - - VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;->newVideoLoaded(Ljava/lang/String;)V") - - with(TextComponentFingerprint - .apply { resolve(context, TextComponentSpecParentFingerprint.result!!.classDef) } - .result ?: return TextComponentFingerprint.toErrorResult() - ) { - val createComponentMethod = mutableMethod - - val conversionContextParam = 5 - val textRefParam = createComponentMethod.parameters.size - 2 - val insertIndex = scanResult.stringsScanResult!!.matches.first().index - 2 - - createComponentMethod.addInstructions( - insertIndex, - """ - move-object/from16 v7, p$conversionContextParam - move-object/from16 v8, p$textRefParam - invoke-static {v7, v8}, Lapp/revanced/integrations/patches/ReturnYouTubeDislikePatch;->onComponentCreated(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;)V - """ - ) - } - return PatchResultSuccess() - } - - private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) - - private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote) - - private enum class Vote(val value: Int) { - LIKE(1), - DISLIKE(-1), - REMOVE_LIKE(0) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt deleted file mode 100644 index 35dd0af7c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/resource/patch/ReturnYouTubeDislikeResourcePatch.kt +++ /dev/null @@ -1,42 +0,0 @@ -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.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.StringResource -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.util.resources.ResourceUtils.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(context: ResourceContext): PatchResult { - val youtubePackage = "com.google.android.youtube" - SettingsPatch.addPreference( - Preference( - StringResource("revanced_ryd_settings_title", "Return YouTube Dislike"), - Preference.Intent( - youtubePackage, - "ryd_settings", - "com.google.android.libraries.social.licenses.LicenseActivity" - ), - StringResource("revanced_ryd_settings_summary", "Settings for Return YouTube Dislike"), - ) - ) - // merge strings - context.mergeStrings("returnyoutubedislike/host/values/strings.xml") - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/fingerprints/SeekbarTappingFingerprint.kt similarity index 91% rename from src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/fingerprints/SeekbarTappingFingerprint.kt index 94d6b2cef..bc84b2c29 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/fingerprints/SeekbarTappingFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.interaction.seekbar.fingerprints +package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object SeekbarTappingFingerprint : MethodFingerprint( "Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/fingerprints/SeekbarTappingParentFingerprint.kt similarity index 94% rename from src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingParentFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/fingerprints/SeekbarTappingParentFingerprint.kt index 20f83effb..1c5003602 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/fingerprints/SeekbarTappingParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/fingerprints/SeekbarTappingParentFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.interaction.seekbar.fingerprints +package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. object SeekbarTappingParentFingerprint : MethodFingerprint( "L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/patch/SeekbarTappingBytecodePatch.kt similarity index 67% rename from src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/patch/SeekbarTappingBytecodePatch.kt index fed792408..0ddbf5f28 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/seekbar/patch/EnableSeekbarTappingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/bytecode/patch/SeekbarTappingBytecodePatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.interaction.seekbar.patch +package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -9,43 +9,25 @@ import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.interaction.seekbar.annotation.SeekbarTappingCompatibility -import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingFingerprint -import app.revanced.patches.youtube.interaction.seekbar.fingerprints.SeekbarTappingParentFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints.SeekbarTappingFingerprint +import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints.SeekbarTappingParentFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.SEEKBAR_LAYOUT import org.jf.dexlib2.builder.instruction.BuilderInstruction21t -import org.jf.dexlib2.iface.Method import org.jf.dexlib2.iface.instruction.formats.Instruction11n import org.jf.dexlib2.iface.instruction.formats.Instruction35c +import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.Opcode -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("seekbar-tapping") -@Description("Enables tap-to-seek on the seekbar of the video player.") -@SeekbarTappingCompatibility +@Name("enable-seekbar-tapping-bytecode-patch") +@YouTubeCompatibility @Version("0.0.1") -class EnableSeekbarTappingPatch : BytecodePatch( +class SeekbarTappingBytecodePatch : BytecodePatch( listOf( SeekbarTappingParentFingerprint, SeekbarTappingFingerprint ) ) { override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.INTERACTIONS.addPreferences( - SwitchPreference( - "revanced_enable_tap_seeking", - StringResource("revanced_seekbar_tapping_enabled_title", "Enable seekbar tapping"), - true, - StringResource("revanced_seekbar_tapping_summary_on", "Seekbar tapping is enabled"), - StringResource("revanced_seekbar_tapping_summary_off", "Seekbar tapping is disabled") - ) - ) - var result = SeekbarTappingParentFingerprint.result!! val tapSeekMethods = mutableMapOf() @@ -101,10 +83,10 @@ class EnableSeekbarTappingPatch : BytecodePatch( ) result.mutableMethod.addInstructions( insertIndex, """ - invoke-static { }, Lapp/revanced/integrations/patches/SeekbarTappingPatch;->isTapSeekingEnabled()Z + invoke-static { }, $SEEKBAR_LAYOUT->enableSeekbarTapping()Z move-result v0 """ ) return PatchResultSuccess() } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/resource/patch/SeekbarTappingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/resource/patch/SeekbarTappingPatch.kt new file mode 100644 index 000000000..307c43a04 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/seekbartapping/resource/patch/SeekbarTappingPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.seekbar.seekbartapping.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.patch.SeekbarTappingBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-seekbar-tapping") +@Description("Enables tap-to-seek on the seekbar of the video player.") +@DependsOn( + [ + SeekbarTappingBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SeekbarTappingPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: SEEKBAR", + "SETTINGS: ENABLE_SEEKBAR_TAPPING" + ) + + ResourceHelper.patchSuccess( + context, + "enable-seekbar-tapping" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/fingerprints/TimeCounterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/bytecode/fingerprints/TimeCounterFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/fingerprints/TimeCounterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/bytecode/fingerprints/TimeCounterFingerprint.kt index 5bd00c510..072c617f1 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hidetimeandseekbar/fingerprints/TimeCounterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/bytecode/fingerprints/TimeCounterFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.hidetimeandseekbar.fingerprints +package app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(3) object TimeCounterFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/bytecode/patch/HideTimeAndSeekbarBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/bytecode/patch/HideTimeAndSeekbarBytecodePatch.kt new file mode 100644 index 000000000..ca7ea1dc7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/bytecode/patch/HideTimeAndSeekbarBytecodePatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints.TimeCounterFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.timebar.HookTimebarPatch +import app.revanced.shared.util.integrations.Constants.SEEKBAR_LAYOUT + +@DependsOn([HookTimebarPatch::class]) +@Name("hide-time-and-seekbar-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class HideTimeAndSeekbarBytecodePatch : BytecodePatch( + listOf( + TimeCounterFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + listOf( + HookTimebarPatch.SetTimbarFingerprintResult, + TimeCounterFingerprint.result!! + ).forEach { result -> + val method = result.mutableMethod + method.addInstructions( + 0, """ + const/4 v0, 0x0 + invoke-static { }, $SEEKBAR_LAYOUT->hideTimeAndSeekbar()Z + move-result v0 + if-eqz v0, :hide_time_and_seekbar + return-void + """, listOf(ExternalLabel("hide_time_and_seekbar", method.instruction(0))) + ) + } + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/resource/patch/HideTimeAndSeekbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/resource/patch/HideTimeAndSeekbarPatch.kt new file mode 100644 index 000000000..f71d1db93 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/layout/seekbar/timeandseekbar/resource/patch/HideTimeAndSeekbarPatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.layout.seekbar.timeandseekbar.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.patch.HideTimeAndSeekbarBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-time-and-seekbar") +@Description("Hides progress bar and time counter on videos.") +@DependsOn( + [ + HideTimeAndSeekbarBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HideTimeAndSeekbarPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings2( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: LAYOUT_SETTINGS", + "PREFERENCE_HEADER: SEEKBAR", + "SETTINGS: HIDE_TIME_AND_SEEKBAR" + ) + + ResourceHelper.patchSuccess( + context, + "hide-time-and-seekbar" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt deleted file mode 100644 index 710fb22b2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/annotations/SponsorBlockCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.sponsorblock.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SponsorBlockCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShortsPlayerConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShortsPlayerConstructorFingerprint.kt deleted file mode 100644 index 862055961..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/ShortsPlayerConstructorFingerprint.kt +++ /dev/null @@ -1,41 +0,0 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.sponsorblock.resource.patch.SponsorBlockResourcePatch -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.WideLiteralInstruction - - -@FuzzyPatternScanMethod(3) -object ShortsPlayerConstructorFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, - opcodes = listOf( - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.MOVE_OBJECT_FROM16, - Opcode.INVOKE_DIRECT_RANGE, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_DIRECT, - Opcode.IPUT_OBJECT, - Opcode.IPUT_OBJECT, - Opcode.CONST_4 - ), - customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { instruction -> - instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == SponsorBlockResourcePatch.reelButtonGroupResourceId - } == true - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt deleted file mode 100644 index 15e40ffc3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt +++ /dev/null @@ -1,293 +0,0 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.fingerprints.SeekbarFingerprint -import app.revanced.patches.shared.fingerprints.SeekbarOnDrawFingerprint -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.youtube.layout.autocaptions.fingerprints.StartVideoInformerFingerprint -import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility -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.playercontrols.bytecode.patch.PlayerControlsBytecodePatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch -import org.jf.dexlib2.Opcode -import org.jf.dexlib2.iface.instruction.* -import org.jf.dexlib2.iface.instruction.formats.Instruction35c -import org.jf.dexlib2.iface.reference.FieldReference -import org.jf.dexlib2.iface.reference.MethodReference -import org.jf.dexlib2.iface.reference.StringReference - -@Patch -@DependsOn( - dependencies = [ - VideoInformationPatch::class, // updates video information and adds method to seek in video - PlayerControlsBytecodePatch::class, - IntegrationsPatch::class, - SponsorBlockResourcePatch::class, - VideoIdPatch::class - ] -) -@Name("sponsorblock") -@Description("Integrate SponsorBlock.") -@SponsorBlockCompatibility -@Version("0.0.1") -class SponsorBlockBytecodePatch : BytecodePatch( - listOf( - SeekbarFingerprint, - NextGenWatchLayoutFingerprint, - AppendTimeFingerprint, - PlayerOverlaysLayoutInitFingerprint, - ShortsPlayerConstructorFingerprint, - StartVideoInformerFingerprint - ) -) { - - private companion object { - const val INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR = - "Lapp/revanced/integrations/sponsorblock/PlayerController;" - } - - override fun execute(context: BytecodeContext): PatchResult { - /* - Hook the video time methods - */ - with(VideoInformationPatch) { - videoTimeHook( - INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR, - "setVideoTime" - ) - highPrecisionTimeHook( - INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR, - "setHighPrecisionVideoTime" - ) - } - - /* - Set current video id - */ - VideoIdPatch.injectCall("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") - - /* - Seekbar drawing - */ - val seekbarSignatureResult = SeekbarFingerprint.result!!.let { - SeekbarOnDrawFingerprint.apply { resolve(context, it.mutableClass) } - }.result!! - val seekbarMethod = seekbarSignatureResult.mutableMethod - val seekbarMethodInstructions = seekbarMethod.implementation!!.instructions - - /* - Get the instance of the seekbar rectangle - */ - for ((index, instruction) in seekbarMethodInstructions.withIndex()) { - if (instruction.opcode != Opcode.MOVE_OBJECT_FROM16) continue - seekbarMethod.addInstruction( - index + 1, - "invoke-static/range {p0 .. p0}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V" - ) - break - } - - for ((index, instruction) in seekbarMethodInstructions.withIndex()) { - if (instruction.opcode != Opcode.INVOKE_STATIC) continue - - val invokeInstruction = instruction as Instruction35c - if ((invokeInstruction.reference as MethodReference).name != "round") continue - - val insertIndex = index + 2 - - // set the thickness of the segment - seekbarMethod.addInstruction( - insertIndex, - "invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V" - ) - break - } - - /* - Set rectangle absolute left and right positions - */ - val drawRectangleInstructions = seekbarMethodInstructions.withIndex().filter { (_, instruction) -> - instruction is ReferenceInstruction && (instruction.reference as? MethodReference)?.name == "drawRect" - }.map { (index, instruction) -> // TODO: improve code - index to (instruction as FiveRegisterInstruction).registerD - } - - val (indexRight, rectangleRightRegister) = drawRectangleInstructions[0] - val (indexLeft, rectangleLeftRegister) = drawRectangleInstructions[3] - - // order of operation is important here due to the code above which has to be improved - // the reason for that is that we get the index, add instructions and then the offset would be wrong - seekbarMethod.addInstruction( - indexLeft + 1, - "invoke-static {v$rectangleLeftRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteLeft(Landroid/graphics/Rect;)V" - ) - seekbarMethod.addInstruction( - indexRight + 1, - "invoke-static {v$rectangleRightRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarAbsoluteRight(Landroid/graphics/Rect;)V" - ) - - /* - Draw segment - */ - val drawSegmentInstructionInsertIndex = (seekbarMethodInstructions.size - 1 - 2) - val (canvasInstance, centerY) = (seekbarMethodInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let { - it.registerC to it.registerE - } - seekbarMethod.addInstruction( - drawSegmentInstructionInsertIndex, - "invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V" - ) - - /* - Voting & Shield button - */ - val controlsMethodResult = PlayerControlsBytecodePatch.showPlayerControlsFingerprintResult - - val controlsLayoutStubResourceId = - ResourceMappingPatch.resourceMappings.single { it.type == "id" && it.name == "controls_layout_stub" }.id - val zoomOverlayResourceId = - ResourceMappingPatch.resourceMappings.single { it.type == "id" && it.name == "video_zoom_overlay_stub" }.id - - methods@ for (method in controlsMethodResult.mutableClass.methods) { - val instructions = method.implementation?.instructions!! - instructions@ for ((index, instruction) in instructions.withIndex()) { - // search for method which inflates the controls layout view - if (instruction.opcode != Opcode.CONST) continue@instructions - - when ((instruction as NarrowLiteralInstruction).wideLiteral) { - controlsLayoutStubResourceId -> { - // replace the view with the YouTubeControlsOverlay - val moveResultInstructionIndex = index + 5 - val inflatedViewRegister = - (instructions[moveResultInstructionIndex] as OneRegisterInstruction).registerA - // initialize with the player overlay object - method.addInstructions( - moveResultInstructionIndex + 1, // insert right after moving the view to the register and use that register - """ - invoke-static {v$inflatedViewRegister}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->initialize(Ljava/lang/Object;)V - invoke-static {v$inflatedViewRegister}, Lapp/revanced/integrations/sponsorblock/VotingButton;->initialize(Ljava/lang/Object;)V - """ - ) - } - - zoomOverlayResourceId -> { - val invertVisibilityMethod = - context.toMethodWalker(method).nextMethod(index - 6, true).getMethod() as MutableMethod - // change visibility of the buttons - invertVisibilityMethod.addInstructions( - 0, """ - invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/ShieldButton;->changeVisibilityNegatedImmediate(Z)V - invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/VotingButton;->changeVisibilityNegatedImmediate(Z)V - """.trimIndent() - ) - } - } - } - } - - // change visibility of the buttons - 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 - NextGenWatchLayoutFingerprint.result!!.mutableMethod.addInstruction( - 3, // after super call - "invoke-static/range {p$instanceRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->addSkipSponsorView15(Landroid/view/View;)V" - ) - - // append the new time to the player layout - val appendTimeFingerprintResult = AppendTimeFingerprint.result!! - val appendTimePatternScanStartIndex = appendTimeFingerprintResult.scanResult.patternScanResult!!.startIndex - val targetRegister = - (appendTimeFingerprintResult.method.implementation!!.instructions.elementAt(appendTimePatternScanStartIndex + 1) as OneRegisterInstruction).registerA - - appendTimeFingerprintResult.mutableMethod.addInstructions( - appendTimePatternScanStartIndex + 2, """ - invoke-static {v$targetRegister}, Lapp/revanced/integrations/sponsorblock/SponsorBlockUtils;->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$targetRegister - """ - ) - - // initialize the player controller - VideoInformationPatch.onCreateHook(INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR, "initialize") - - // initialize the sponsorblock view - PlayerOverlaysLayoutInitFingerprint.result!!.mutableMethod.addInstruction( - 6, // after inflating the view - "invoke-static {p0}, Lapp/revanced/integrations/sponsorblock/player/ui/SponsorBlockView;->initialize(Ljava/lang/Object;)V" - ) - - // get rectangle field name - RectangleFieldInvalidatorFingerprint.resolve(context, seekbarSignatureResult.classDef) - val rectangleFieldInvalidatorInstructions = - RectangleFieldInvalidatorFingerprint.result!!.method.implementation!!.instructions - val rectangleFieldName = - ((rectangleFieldInvalidatorInstructions.elementAt(rectangleFieldInvalidatorInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name - - // replace the "replaceMeWith*" strings - context - .proxy(context.classes.first { it.type.endsWith("PlayerController;") }) - .mutableClass - .methods - .find { it.name == "setSponsorBarRect" } - ?.let { method -> - fun MutableMethod.replaceStringInstruction(index: Int, instruction: Instruction, with: String) { - val register = (instruction as OneRegisterInstruction).registerA - this.replaceInstruction( - index, "const-string v$register, \"$with\"" - ) - } - for ((index, it) in method.implementation!!.instructions.withIndex()) { - if (it.opcode.ordinal != Opcode.CONST_STRING.ordinal) continue - - when (((it as ReferenceInstruction).reference as StringReference).string) { - "replaceMeWithsetSponsorBarRect" -> - method.replaceStringInstruction(index, it, rectangleFieldName) - - "replaceMeWithsetMillisecondMethod" -> - method.replaceStringInstruction(index, it, "seekHelper") - } - } - } ?: return PatchResultError("Could not find the method which contains the replaceMeWith* strings") - - val startVideoInformerMethod = StartVideoInformerFingerprint.result!!.mutableMethod - startVideoInformerMethod.addInstructions( - 0, """ - const/4 v0, 0x0 - sput-boolean v0, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->shorts_playing:Z - """ - ) - - val shortsPlayerConstructorMethod = ShortsPlayerConstructorFingerprint.result!!.mutableMethod - - shortsPlayerConstructorMethod.addInstructions( - 0, """ - const/4 v0, 0x1 - sput-boolean v0, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->shorts_playing:Z - """ - ) - - // TODO: isSBChannelWhitelisting implementation - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt deleted file mode 100644 index 7b0d58f61..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt +++ /dev/null @@ -1,116 +0,0 @@ -package app.revanced.patches.youtube.layout.sponsorblock.resource.patch - -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.youtube.layout.sponsorblock.annotations.SponsorBlockCompatibility -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources -import app.revanced.util.resources.ResourceUtils.copyXmlNode -import app.revanced.util.resources.ResourceUtils.mergeStrings - -@Name("sponsorblock-resource-patch") -@SponsorBlockCompatibility -@DependsOn([FixLocaleConfigErrorPatch::class, SettingsPatch::class, ResourceMappingPatch::class]) -@Version("0.0.1") -class SponsorBlockResourcePatch : ResourcePatch { - companion object { - internal var reelButtonGroupResourceId: Long = 0 - } - - override fun execute(context: ResourceContext): PatchResult { - val youtubePackage = "com.google.android.youtube" - SettingsPatch.addPreference( - Preference( - StringResource("sb_settings", "SponsorBlock"), - Preference.Intent( - youtubePackage, - "sponsorblock_settings", - "com.google.android.libraries.social.licenses.LicenseActivity" - ), - StringResource("revanced_sponsorblock_settings_summary", "SponsorBlock related settings"), - ) - ) - val classLoader = this.javaClass.classLoader - - /* - merge SponsorBlock strings to main strings - */ - context.mergeStrings("sponsorblock/host/values/strings.xml") - - /* - merge SponsorBlock drawables to main drawables - */ - - 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 -> - context.copyResources("sponsorblock", resourceGroup) - } - - /* - merge xml nodes from the host to their real xml files - */ - - // copy nodes from host resources to their real xml files - val hostingResourceStream = - classLoader.getResourceAsStream("sponsorblock/host/layout/youtube_controls_layout.xml")!! - - val targetXmlEditor = context.xmlEditor["res/layout/youtube_controls_layout.xml"] - "RelativeLayout".copyXmlNode( - context.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 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" - - view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = votingButtonId - - break - } - }.close() // close afterwards - - reelButtonGroupResourceId = ResourceMappingPatch.resourceMappings.single { - it.type == "id" && it.name == "reel_persistent_edu_button_group" - }.id - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt deleted file mode 100644 index c974f4996..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/annotations/StartupShortsResetCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.startupshortsreset.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class StartupShortsResetCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt deleted file mode 100644 index 924c07899..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/startupshortsreset/patch/DisableShortsOnStartupPatch.kt +++ /dev/null @@ -1,59 +0,0 @@ -package app.revanced.patches.youtube.layout.startupshortsreset.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.startupshortsreset.annotations.StartupShortsResetCompatibility -import app.revanced.patches.youtube.layout.startupshortsreset.fingerprints.UserWasInShortsFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("disable-startup-shorts-player") -@Description("Disables playing YouTube Shorts when launching YouTube.") -@StartupShortsResetCompatibility -@Version("0.0.1") -class DisableShortsOnStartupPatch : BytecodePatch( - listOf( - UserWasInShortsFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_startup_shorts_player_enabled", - StringResource("revanced_startup_shorts_player_title", "Disable shorts player at app startup"), - false, - StringResource("revanced_startup_shorts_player_summary_on", "Shorts player is disabled at app startup"), - StringResource("revanced_startup_shorts_player_summary_off", "Shorts player is enabled at app startup") - ) - ) - - val userWasInShortsResult = UserWasInShortsFingerprint.result!! - val userWasInShortsMethod = userWasInShortsResult.mutableMethod - val moveResultIndex = userWasInShortsResult.scanResult.patternScanResult!!.endIndex - - userWasInShortsMethod.addInstructions( - moveResultIndex + 1, """ - invoke-static { }, Lapp/revanced/integrations/patches/DisableStartupShortsPlayerPatch;->disableStartupShortsPlayer()Z - move-result v5 - if-eqz v5, :disable_shorts_player - return-void - :disable_shorts_player - nop - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt deleted file mode 100644 index 8d5a0fb51..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/tabletminiplayer/annotations/TabletMiniPlayerCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.tabletminiplayer.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class TabletMiniPlayerCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/annotations/ThemeCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/annotations/ThemeCompatibility.kt deleted file mode 100644 index 5bf335060..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/annotations/ThemeCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.theme.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ThemeCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt deleted file mode 100644 index 919342c5e..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/ThemePatch.kt +++ /dev/null @@ -1,74 +0,0 @@ -package app.revanced.patches.youtube.layout.theme.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.* -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources -import org.w3c.dom.Element - -@Patch(include = false) -@DependsOn([LithoThemePatch::class, FixLocaleConfigErrorPatch::class]) -@Name("theme") -@Description("Applies a custom theme.") -@ThemeCompatibility -@Version("0.0.1") -class ThemePatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - val darkThemeBackgroundColor = darkThemeBackgroundColor!! - val lightThemeBackgroundColor = lightThemeBackgroundColor!! - - context.xmlEditor["res/values/colors.xml"].use { editor -> - val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element - - for (i in 0 until resourcesNode.childNodes.length) { - val node = resourcesNode.childNodes.item(i) as? Element ?: continue - - node.textContent = when (node.getAttribute("name")) { - "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3", - "yt_black4", "yt_status_bar_background_dark", "material_grey_100", "material_grey_50", - "material_grey_600", "material_grey_800", "material_grey_850", "material_grey_900", - "material_grey_white_1000", "sud_glif_v3_dialog_background_color_dark" -> darkThemeBackgroundColor - - "yt_white1", "yt_white1_opacity95", "yt_white1_opacity98", "yt_white2", "yt_white3", "yt_white4", - "sud_glif_v3_dialog_background_color_light" -> lightThemeBackgroundColor - - else -> continue - } - } - } - - // copies the resource file to change the splash screen color - context.copyResources("theme", - ResourceUtils.ResourceGroup("values-night-v31", "styles.xml") - ) - - return PatchResultSuccess() - } - - companion object : OptionsContainer() { - var darkThemeBackgroundColor: String? by option( - PatchOption.StringOption( - key = "darkThemeBackgroundColor", - default = "@android:color/black", - title = "Background color for the dark theme", - description = "The background color of the dark theme. Can be a hex color or a resource reference.", - ) - ) - - var lightThemeBackgroundColor: String? by option( - PatchOption.StringOption( - key = "lightThemeBackgroundColor", - default = "@android:color/white", - title = "Background color for the light theme", - description = "The background color of the light theme. Can be a hex color or a resource reference.", - ) - ) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/annotations/WatchinVRCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/annotations/WatchinVRCompatibility.kt deleted file mode 100644 index 313a0df03..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/annotations/WatchinVRCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.watchinvr.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class WatchinVRCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/fingerprints/WatchinVRFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/fingerprints/WatchinVRFingerprint.kt deleted file mode 100644 index febf7b3a7..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/fingerprints/WatchinVRFingerprint.kt +++ /dev/null @@ -1,10 +0,0 @@ -package app.revanced.patches.youtube.layout.watchinvr.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object WatchinVRFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), - strings = listOf("menu_item_cardboard_vr") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/patch/WatchinVRPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/patch/WatchinVRPatch.kt deleted file mode 100644 index d2915f3bc..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watchinvr/patch/WatchinVRPatch.kt +++ /dev/null @@ -1,55 +0,0 @@ -package app.revanced.patches.youtube.layout.watchinvr.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.watchinvr.annotations.WatchinVRCompatibility -import app.revanced.patches.youtube.layout.watchinvr.fingerprints.WatchinVRFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("hide-watch-in-vr") -@Description("Hides the Watch in VR option in the player settings flyout panel.") -@WatchinVRCompatibility -@Version("0.0.1") -class WatchinVRPatch : BytecodePatch( - listOf( - WatchinVRFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_watch_in_vr", - StringResource("revanced_hide_watch_in_vr_title", "Hide watch in VR"), - false, - StringResource("revanced_hide_watch_in_vr_summary_on", "Watch in VR player setting is hidden"), - StringResource("revanced_hide_watch_in_vr_summary_off", "Watch in VR player setting is shown") - ) - ) - - WatchinVRFingerprint.result!!.mutableMethod.addInstructions( - 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/HideWatchinVRPatch;->hideWatchinVR()Z - move-result v0 - if-eqz v0, :shown - return-void - :shown - nop - """ - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/annotations/HideWaterwarkCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/annotations/HideWaterwarkCompatibility.kt deleted file mode 100644 index 509e14610..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/annotations/HideWaterwarkCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.watermark.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HideWatermarkCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/fingerprints/HideWatermarkParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/fingerprints/HideWatermarkParentFingerprint.kt deleted file mode 100644 index 9d0375882..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/fingerprints/HideWatermarkParentFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.layout.watermark.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object HideWatermarkParentFingerprint : MethodFingerprint ( - "L", AccessFlags.PUBLIC or AccessFlags.FINAL, strings = listOf("player_overlay_in_video_programming") -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt deleted file mode 100644 index ec5c1b310..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/watermark/patch/HideWatermarkPatch.kt +++ /dev/null @@ -1,63 +0,0 @@ -package app.revanced.patches.youtube.layout.watermark.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.watermark.annotations.HideWatermarkCompatibility -import app.revanced.patches.youtube.layout.watermark.fingerprints.HideWatermarkFingerprint -import app.revanced.patches.youtube.layout.watermark.fingerprints.HideWatermarkParentFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("hide-watermark") -@Description("Hides creator's watermarks on videos.") -@HideWatermarkCompatibility -@Version("0.0.1") -class HideWatermarkPatch : BytecodePatch( - listOf( - HideWatermarkParentFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_hide_video_watermark", - StringResource("revanced_hide_video_watermark_title", "Hide creator watermark on videos"), - true, - StringResource("revanced_hide_video_watermark_summary_on", "Watermark is hidden"), - StringResource("revanced_hide_video_watermark_summary_off", "Watermark is shown") - ) - ) - - HideWatermarkFingerprint.resolve(context, HideWatermarkParentFingerprint.result!!.classDef) - val result = HideWatermarkFingerprint.result - ?: return PatchResultError("Required parent method could not be found.") - - val method = result.mutableMethod - val line = method.implementation!!.instructions.size - 5 - - method.removeInstruction(line) - method.addInstructions( - line, """ - invoke-static {}, Lapp/revanced/integrations/patches/BrandingWaterMarkPatch;->isBrandingWatermarkShown()Z - move-result p2 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/annotations/WideSearchbarCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/annotations/WideSearchbarCompatibility.kt deleted file mode 100644 index 2a070b2bb..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/annotations/WideSearchbarCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.layout.widesearchbar.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class WideSearchbarCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/SetWordmarkHeaderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/SetWordmarkHeaderFingerprint.kt deleted file mode 100644 index 84ee99988..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/SetWordmarkHeaderFingerprint.kt +++ /dev/null @@ -1,22 +0,0 @@ -package app.revanced.patches.youtube.layout.widesearchbar.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object SetWordmarkHeaderFingerprint : MethodFingerprint( - "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), - opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.IF_NEZ, - Opcode.IGET_BOOLEAN, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.CONST, - Opcode.INVOKE_STATIC, - ), - customFingerprint = { methodDef -> methodDef.parameterTypes.first() == "Landroid/widget/ImageView;" } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt deleted file mode 100644 index 50263ba00..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/patch/WideSearchbarPatch.kt +++ /dev/null @@ -1,88 +0,0 @@ -package app.revanced.patches.youtube.layout.widesearchbar.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.layout.widesearchbar.annotations.WideSearchbarCompatibility -import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.DrawActionBarFingerprint -import app.revanced.patches.youtube.layout.widesearchbar.fingerprints.SetWordmarkHeaderFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("enable-wide-searchbar") -@Description("Replaces the search icon with a wide search bar. This will hide the YouTube logo when active.") -@WideSearchbarCompatibility -@Version("0.0.1") -class WideSearchbarPatch : BytecodePatch( - listOf( - SetWordmarkHeaderFingerprint, DrawActionBarFingerprint - ) -) { - private companion object { - /** - * Walk a fingerprints method at a given index mutably. - * - * @param index The index to walk at. - * @param fromFingerprint The fingerprint to walk the method on. - * @return The [MutableMethod] which was walked on. - */ - fun BytecodeContext.walkMutable(index: Int, fromFingerprint: MethodFingerprint) = - fromFingerprint.result?.let { - toMethodWalker(it.method).nextMethod(index, true).getMethod() as MutableMethod - } ?: throw SetWordmarkHeaderFingerprint.toErrorResult() - - - /** - * Injects instructions required for certain methods. - * - */ - fun MutableMethod.injectSearchBarHook() { - addInstructions( - implementation!!.instructions.size - 1, - """ - invoke-static {}, Lapp/revanced/integrations/patches/NewActionbarPatch;->getNewActionBar()Z - move-result p0 - """ - ) - } - } - - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.LAYOUT.addPreferences( - SwitchPreference( - "revanced_wide_searchbar", - StringResource("revanced_wide_searchbar_enabled_title", "Enable wide search bar"), - false, - StringResource("revanced_wide_searchbar_summary_on", "Wide search bar is enabled"), - StringResource("revanced_wide_searchbar_summary_off", "Wide search bar is disabled") - ) - ) - - val result = DrawActionBarFingerprint.result ?: return DrawActionBarFingerprint.toErrorResult() - - // patch methods - mapOf( - SetWordmarkHeaderFingerprint to 1, - DrawActionBarFingerprint to result.scanResult.patternScanResult!!.endIndex - ).forEach { (fingerprint, callIndex) -> - context.walkMutable(callIndex, fingerprint).injectSearchBarHook() - } - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt deleted file mode 100644 index 18de2e6dd..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/annotations/AutoRepeatCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.autorepeat.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class AutoRepeatCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt deleted file mode 100644 index 38617967d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/autorepeat/patch/AutoRepeatPatch.kt +++ /dev/null @@ -1,88 +0,0 @@ -package app.revanced.patches.youtube.misc.autorepeat.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.removeInstruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.autorepeat.annotations.AutoRepeatCompatibility -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.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference - -@Patch -@DependsOn([IntegrationsPatch::class]) -@Name("always-autorepeat") -@Description("Always repeats the playing video again.") -@AutoRepeatCompatibility -@Version("0.0.1") -class AutoRepeatPatch : BytecodePatch( - listOf( - AutoRepeatParentFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_pref_auto_repeat", - StringResource("revanced_auto_repeat_enabled_title", "Enable auto-repeat"), - false, - 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.") - - //this one needs to be called when app/revanced/integrations/patches/AutoRepeatPatch;->shouldAutoRepeat() returns true - val playMethod = parentResult.mutableMethod - AutoRepeatFingerprint.resolve(context, parentResult.classDef) - //String is: Laamp;->E()V - val methodToCall = playMethod.definingClass + "->" + playMethod.name + "()V"; - - //This is the method we search for - val result = AutoRepeatFingerprint.result - ?: return PatchResultError("FingerPrint did not resolve.") - val method = result.mutableMethod - - //Instructions to add to the smali code - val instructions = """ - invoke-static {}, Lapp/revanced/integrations/patches/AutoRepeatPatch;->shouldAutoRepeat()Z - move-result v0 - if-eqz v0, :noautorepeat - invoke-virtual {p0}, $methodToCall - :noautorepeat - return-void - """ - - //Get the implementation so we can do a check for null and get instructions size. - val implementation = method.implementation - ?: return PatchResultError("No Method Implementation found!") - - //Since addInstructions needs an index which starts counting at 0 and size starts counting at 1, - //we have to remove 1 to get the latest instruction - val index = implementation.instructions.size - 1 - - - //remove last instruction which is return-void - method.removeInstruction(index) - // Add our own instructions there - method.addInstructions(index, instructions) - - //Everything worked as expected, return Success - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Blue.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Blue.kt new file mode 100644 index 000000000..184259074 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Blue.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.youtube.misc.branding.icon.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.IconHelper +import app.revanced.shared.util.resources.ResourceHelper + +@Patch(false) +@Name("custom-branding-icon-blue") +@Description("Changes the YouTube launcher icon (ReVanced Blue).") +@DependsOn([SettingsPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class CustomBrandingPatch_Blue : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + IconHelper.customIcon( + context, + "blue" + ) + + ResourceHelper.iconPatchSuccess( + context, + "blue" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Red.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Red.kt new file mode 100644 index 000000000..1148ab8d3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Red.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.youtube.misc.branding.icon.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.IconHelper +import app.revanced.shared.util.resources.ResourceHelper + +@Patch(false) +@Name("custom-branding-icon-red") +@Description("Changes the YouTube launcher icon (ReVanced Red).") +@DependsOn([SettingsPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class CustomBrandingPatch_Red : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + IconHelper.customIcon( + context, + "red" + ) + + ResourceHelper.iconPatchSuccess( + context, + "red" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Revancify.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Revancify.kt new file mode 100644 index 000000000..ebd07473b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/icon/patch/CustomBrandingPatch_Revancify.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.youtube.misc.branding.icon.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.IconHelper +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("custom-branding-icon-revancify") +@Description("Changes the YouTube launcher icon (Revancify).") +@DependsOn([SettingsPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class CustomBrandingPatch_Revancify : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + IconHelper.customIcon( + context, + "revancify" + ) + + ResourceHelper.iconPatchSuccess( + context, + "revancify" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/branding/name/patch/CustomBrandingNamePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/name/patch/CustomBrandingNamePatch.kt new file mode 100644 index 000000000..d0795db6f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/branding/name/patch/CustomBrandingNamePatch.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.youtube.misc.branding.name.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.startsWithAny +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.resources.ResourceHelper +import org.w3c.dom.Element + +@Patch +@Name("custom-branding-name") +@DependsOn( + [ + PatchOptions::class, + SettingsPatch::class + ] +) +@Description("Changes the YouTube launcher name to your choice (defaults to ReVanced Extended).") +@YouTubeCompatibility +@Version("0.0.1") +class CustomBrandingNamePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + // App name + val resourceFileNames = arrayOf("strings.xml") + var appName = PatchOptions.YouTube_AppName + + context.forEach { + if (!it.name.startsWithAny(*resourceFileNames)) return@forEach + + // for each file in the "layouts" directory replace all necessary attributes content + context.xmlEditor[it.absolutePath].use { editor -> + val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) + if (node !is Element) continue + + val element = resourcesNode.childNodes.item(i) as Element + element.textContent = when (element.getAttribute("name")) { + "application_name" -> "$appName" + else -> continue + } + } + } + } + + ResourceHelper.labelPatchSuccess( + context, + "$appName" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/bytecode/fingerprints/UserAgentHeaderBuilderFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/bytecode/fingerprints/UserAgentHeaderBuilderFingerprint.kt index 0c1dcdbdd..8ac6f34f0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/fingerprints/UserAgentHeaderBuilderFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/bytecode/fingerprints/UserAgentHeaderBuilderFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.fix.spoof.fingerprints - +package app.revanced.patches.youtube.misc.clientspoof.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/bytecode/patch/ClientSpoofBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/bytecode/patch/ClientSpoofBytecodePatch.kt new file mode 100644 index 000000000..320e9e194 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/bytecode/patch/ClientSpoofBytecodePatch.kt @@ -0,0 +1,33 @@ +package app.revanced.patches.youtube.misc.clientspoof.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.clientspoof.bytecode.fingerprints.UserAgentHeaderBuilderFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction + +@Name("client-spoof-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class ClientSpoofBytecodePatch : BytecodePatch( + listOf(UserAgentHeaderBuilderFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + val result = UserAgentHeaderBuilderFingerprint.result!! + val method = result.mutableMethod + + val insertIndex = result.scanResult.patternScanResult!!.endIndex + val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD + + val originalPackageName = "com.google.android.youtube" + method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/resource/patch/ClientSpoofPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/resource/patch/ClientSpoofPatch.kt new file mode 100644 index 000000000..10f3c842b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/clientspoof/resource/patch/ClientSpoofPatch.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.youtube.misc.clientspoof.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.clientspoof.bytecode.patch.ClientSpoofBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("client-spoof") +@Description("Spoofs the YouTube client to prevent playback issues.") +@DependsOn( + [ + ClientSpoofBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ClientSpoofPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + ResourceHelper.patchSuccess( + context, + "client-spoof" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/MaxBufferFingerprint.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/MaxBufferFingerprint.kt index 9f194e951..ee65c07aa 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/MaxBufferFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/MaxBufferFingerprint.kt @@ -1,10 +1,10 @@ -package app.revanced.patches.youtube.misc.videobuffer.fingerprints +package app.revanced.patches.youtube.misc.customvideobuffer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction +import org.jf.dexlib2.Opcode object MaxBufferFingerprint : MethodFingerprint( "I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/PlaybackBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/PlaybackBufferFingerprint.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/PlaybackBufferFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/PlaybackBufferFingerprint.kt index b4de74358..6feb1bad2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/PlaybackBufferFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/PlaybackBufferFingerprint.kt @@ -1,10 +1,10 @@ -package app.revanced.patches.youtube.misc.videobuffer.fingerprints +package app.revanced.patches.youtube.misc.customvideobuffer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction +import org.jf.dexlib2.Opcode object PlaybackBufferFingerprint : MethodFingerprint( "I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/ReBufferFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/ReBufferFingerprint.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/ReBufferFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/ReBufferFingerprint.kt index d9754ddec..904430796 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/fingerprints/ReBufferFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/fingerprints/ReBufferFingerprint.kt @@ -1,10 +1,10 @@ -package app.revanced.patches.youtube.misc.videobuffer.fingerprints +package app.revanced.patches.youtube.misc.customvideobuffer.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction +import org.jf.dexlib2.Opcode object ReBufferFingerprint : MethodFingerprint( "I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/patch/CustomVideoBufferBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/patch/CustomVideoBufferBytecodePatch.kt new file mode 100644 index 000000000..1f13c5151 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/bytecode/patch/CustomVideoBufferBytecodePatch.kt @@ -0,0 +1,88 @@ +package app.revanced.patches.youtube.misc.customvideobuffer.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.misc.customvideobuffer.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.MISC_PATH +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("custom-video-buffer-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class CustomVideoBufferBytecodePatch : BytecodePatch( + listOf( + MaxBufferFingerprint, + PlaybackBufferFingerprint, + ReBufferFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + execMaxBuffer() + execPlaybackBuffer() + execReBuffer() + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_BUFFER_CLASS_DESCRIPTOR = + "$MISC_PATH/CustomVideoBufferPatch;" + } + private fun execMaxBuffer() { + val (method, result) = MaxBufferFingerprint.unwrap(true, -1) + val (index, register) = result + + method.addInstructions( + index + 1, """ + invoke-static {}, $INTEGRATIONS_BUFFER_CLASS_DESCRIPTOR->setMaxBuffer()I + move-result v$register + """ + ) + } + + private fun execPlaybackBuffer() { + val (method, result) = PlaybackBufferFingerprint.unwrap() + val (index, register) = result + + method.addInstructions( + index + 1, """ + invoke-static {}, $INTEGRATIONS_BUFFER_CLASS_DESCRIPTOR->setPlaybackBuffer()I + move-result v$register + """ + ) + } + + private fun execReBuffer() { + val (method, result) = ReBufferFingerprint.unwrap() + val (index, register) = result + + method.addInstructions( + index + 1, """ + invoke-static {}, $INTEGRATIONS_BUFFER_CLASS_DESCRIPTOR->setReBuffer()I + move-result v$register + """ + ) + } + + private fun MethodFingerprint.unwrap( + forEndIndex: Boolean = false, + offset: Int = 0 + ): Pair> { + val result = this.result!! + val method = result.mutableMethod + val scanResult = result.scanResult.patternScanResult!! + val index = (if (forEndIndex) scanResult.endIndex else scanResult.startIndex) + offset + + val register = (method.instruction(index) as OneRegisterInstruction).registerA + + return method to (index to register) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/resource/patch/CustomVideoBufferPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/resource/patch/CustomVideoBufferPatch.kt new file mode 100644 index 000000000..cca0123b6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/customvideobuffer/resource/patch/CustomVideoBufferPatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.misc.customvideobuffer.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.customvideobuffer.bytecode.patch.CustomVideoBufferBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("custom-video-buffer") +@Description("Lets you change the buffers of videos.") +@DependsOn( + [ + CustomVideoBufferBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class CustomVideoBufferPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: MISC_SETTINGS", + "SETTINGS: CUSTOM_VIDEO_BUFFER" + ) + + ResourceHelper.patchSuccess( + context, + "custom-video-buffer" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/annotations/DebuggingCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/annotations/DebuggingCompatibility.kt deleted file mode 100644 index cac120bcf..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/annotations/DebuggingCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.debugging.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class DebuggingCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt deleted file mode 100644 index 34cdde221..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/debugging/patch/DebuggingPatch.kt +++ /dev/null @@ -1,77 +0,0 @@ -package app.revanced.patches.youtube.misc.debugging.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.* -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.misc.debugging.annotations.DebuggingCompatibility -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import org.w3c.dom.Element - -@Patch -@Name("debugging") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Description("Adds debugging options.") -@DebuggingCompatibility -@Version("0.0.1") -class DebuggingPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - app.revanced.patches.shared.settings.preference.impl.PreferenceScreen( - "revanced_debug", - StringResource("revanced_debug_title", "Debugging"), - listOf( - SwitchPreference( - "revanced_debug_enabled", - StringResource("revanced_debug_enabled_title", "Enable debug logs"), - false, - StringResource("revanced_debug_summary_on", "Debug logs are enabled"), - StringResource("revanced_debug_summary_off", "Debug logs are disabled") - ), - SwitchPreference( - "revanced_debug_stacktrace_enabled", - StringResource( - "revanced_debug_stacktrace_enabled_title", - "Print stack traces" - ), - false, - StringResource("revanced_debug_stacktrace_summary_on", "Enabled printing stack traces"), - StringResource("revanced_debug_stacktrace_summary_off", "Disabled printing stack traces") - ), - ), - StringResource("revanced_debug_summary", "Enable or disable debugging options") - ) - ) - - if (debuggable == true) { - context.xmlEditor["AndroidManifest.xml"].use { dom -> - val applicationNode = dom - .file - .getElementsByTagName("application") - .item(0) as Element - - // set application as debuggable - applicationNode.setAttribute("android:debuggable", "true") - } - } - - return PatchResultSuccess() - } - - companion object : OptionsContainer() { - var debuggable: Boolean? by option( - PatchOption.BooleanOption( - key = "debuggable", - default = false, - title = "App debugging", - description = "Whether to make the app debuggable on Android.", - ) - ) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/RecyclerViewFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/RecyclerViewFingerprint.kt new file mode 100644 index 000000000..99266d540 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/RecyclerViewFingerprint.kt @@ -0,0 +1,22 @@ +package app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object RecyclerViewFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("I"), + opcodes = listOf( + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, + Opcode.IF_NEZ, + ), + strings = listOf("Cannot scroll to position a LayoutManager set. Call setLayoutManager with a non-null argument."), + customFingerprint = { methodDef -> + methodDef.definingClass == "Landroid/support/v7/widget/RecyclerView;" + } +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/ScrollPositionFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/ScrollPositionFingerprint.kt new file mode 100644 index 000000000..3647ab2e1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/fingerprint/ScrollPositionFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ScrollPositionFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PROTECTED or AccessFlags.FINAL, + parameters = listOf("L"), + opcodes = listOf( + Opcode.IF_NEZ, + Opcode.INVOKE_DIRECT, + Opcode.RETURN_VOID + ), + strings = listOf("scroll_position") +) + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/patch/DoubleBackToExitPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/patch/DoubleBackToExitPatch.kt new file mode 100644 index 000000000..d879f4ab7 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/doublebacktoexit/patch/DoubleBackToExitPatch.kt @@ -0,0 +1,71 @@ +package app.revanced.patches.youtube.misc.doublebacktoexit.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint.RecyclerViewFingerprint +import app.revanced.patches.youtube.misc.doublebacktoexit.fingerprint.ScrollPositionFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.toErrorResult +import app.revanced.shared.patches.gestures.PredictiveBackGesturePatch +import app.revanced.shared.util.bytecode.BytecodeHelper +import app.revanced.shared.util.integrations.Constants.UTILS_PATH + +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.Opcode + +@Name("enable-double-back-to-exit") +@Description("Enable double back to exit.") +@YouTubeCompatibility +@Version("0.0.1") +@DependsOn([PredictiveBackGesturePatch::class]) +class DoubleBackToExitPatch : BytecodePatch( + listOf( + RecyclerViewFingerprint, + ScrollPositionFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val DTE_CLASS_DESCRIPTOR = "$UTILS_PATH/DoubleBackToExitPatch;" + + val scrollPositionResult = ScrollPositionFingerprint.result!! + val scrollPositionMethod = + context.toMethodWalker(scrollPositionResult.method) + .nextMethod(scrollPositionResult.scanResult.patternScanResult!!.startIndex + 1, true) + .getMethod() as MutableMethod + val backToExitInstructions = scrollPositionMethod.implementation!!.instructions + + for ((index, instruction) in backToExitInstructions.withIndex()) { + if (instruction.opcode != Opcode.CONST_4) continue + + scrollPositionMethod.addInstruction( + index + 2, + "invoke-static {}, $DTE_CLASS_DESCRIPTOR->onCreate()V" + ) + + break + } + + val recyclerViewResult = RecyclerViewFingerprint.result ?: return RecyclerViewFingerprint.toErrorResult() + val recyclerViewMethod = recyclerViewResult.mutableMethod + val recyclerViewEndIndex = recyclerViewResult.scanResult.patternScanResult!!.endIndex + + recyclerViewMethod.addInstruction( + recyclerViewEndIndex, + "invoke-static {}, $DTE_CLASS_DESCRIPTOR->onDestroy()V" + ) + + BytecodeHelper.injectBackPressed(context) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserPrimaryFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserPrimaryFingerprint.kt new file mode 100644 index 000000000..8920a6b99 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserPrimaryFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ExternalBrowserPrimaryFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( + Opcode.CHECK_CAST, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.CONST_STRING + ), + strings = listOf("android.support.customtabs.action.CustomTabsService") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserSecondaryFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserSecondaryFingerprint.kt new file mode 100644 index 000000000..7ee275dc3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserSecondaryFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ExternalBrowserSecondaryFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf( + Opcode.IPUT_OBJECT, + Opcode.NEW_INSTANCE, + Opcode.CONST_STRING + ), + strings = listOf("android.support.customtabs.action.CustomTabsService") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserTertiaryFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserTertiaryFingerprint.kt new file mode 100644 index 000000000..2f9c7a7cd --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/fingerprints/ExternalBrowserTertiaryFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object ExternalBrowserTertiaryFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, opcodes = listOf( + Opcode.CHECK_CAST, + Opcode.NEW_INSTANCE, + Opcode.INVOKE_DIRECT, + Opcode.CONST_STRING + ), + strings = listOf("android.support.customtabs.action.CustomTabsService") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/patch/ExternalBrowserBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/patch/ExternalBrowserBytecodePatch.kt new file mode 100644 index 000000000..a2bc3c136 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/bytecode/patch/ExternalBrowserBytecodePatch.kt @@ -0,0 +1,49 @@ +package app.revanced.patches.youtube.misc.externalbrowser.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.MISC_PATH +import org.jf.dexlib2.iface.instruction.formats.Instruction21c + +@Name("enable-external-browser-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class ExternalBrowserBytecodePatch : BytecodePatch( + listOf( + ExternalBrowserPrimaryFingerprint, + ExternalBrowserSecondaryFingerprint, + ExternalBrowserTertiaryFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + arrayOf( + ExternalBrowserPrimaryFingerprint, + ExternalBrowserSecondaryFingerprint, + ExternalBrowserTertiaryFingerprint + ).forEach { fingerprint -> + val result = fingerprint.result!! + val method = result.mutableMethod + val endIndex = result.scanResult.patternScanResult!!.endIndex + val register = (method.implementation!!.instructions[endIndex] as Instruction21c).registerA + + method.addInstructions( + endIndex + 1, """ + invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$register + """ + ) + } + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/resource/patch/ExternalBrowserPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/resource/patch/ExternalBrowserPatch.kt new file mode 100644 index 000000000..cb5ea26f2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/externalbrowser/resource/patch/ExternalBrowserPatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.misc.externalbrowser.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.externalbrowser.bytecode.patch.ExternalBrowserBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-external-browser") +@Description("Use an external browser to open the url.") +@DependsOn( + [ + ExternalBrowserBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ExternalBrowserPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: MISC_SETTINGS", + "SETTINGS: ENABLE_EXTERNAL_BROWSER" + ) + + ResourceHelper.patchSuccess( + context, + "enable-external-browser" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/FixPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/FixPlaybackCompatibility.kt deleted file mode 100644 index 8a2bb4613..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/annotations/FixPlaybackCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class FixPlaybackCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/FixPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/FixPlaybackPatch.kt deleted file mode 100644 index 148395672..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/patch/FixPlaybackPatch.kt +++ /dev/null @@ -1,52 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.misc.fix.playback.annotations.FixPlaybackCompatibility -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.youtube.misc.video.information.patch.VideoInformationPatch -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch - -@DependsOn([ - IntegrationsPatch::class, - VideoInformationPatch::class, // updates video length and adds method to seek in video, necessary for this patch - SettingsPatch::class, - VideoIdPatch::class -]) -@Name("fix-playback") -@Description("Fixes the issue with videos not playing when video ads are removed.") -@FixPlaybackCompatibility -@Version("0.0.1") -class FixPlaybackPatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_fix_playback", - StringResource("revanced_fix_playback_title", "Fix video playback issues"), - false, - StringResource( - "revanced_fix_playback_summary_on", - "The fix is enabled" - ), - StringResource( - "revanced_fix_playback_summary_off", - "The fix is disabled" - ) - ) - ) - - // If a new video loads, fix the playback issue - VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/FixPlaybackPatch;->newVideoLoaded(Ljava/lang/String;)V") - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/annotations/ClientSpoofCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/annotations/ClientSpoofCompatibility.kt deleted file mode 100644 index 9d2760bda..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/spoof/annotations/ClientSpoofCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.spoof.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.google.android.youtube"), - Package("com.vanced.android.youtube") - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ClientSpoofCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/annotations/VerticalScrollCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/annotations/VerticalScrollCompatibility.kt deleted file mode 100644 index 12a4b74b5..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/annotations/VerticalScrollCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.verticalscroll.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [ - Package("com.google.android.youtube"), - ] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class VerticalScrollCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt deleted file mode 100644 index 1f8792482..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/fingerprints/CanScrollVerticallyFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.verticalscroll.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object CanScrollVerticallyFingerprint : MethodFingerprint( - "Z", - parameters = emptyList(), - opcodes = listOf(Opcode.INSTANCE_OF), - customFingerprint = { methodDef -> methodDef.definingClass.endsWith("SwipeRefreshLayout;") } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt deleted file mode 100644 index 3619ea653..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/verticalscroll/patch/VerticalScrollPatch.kt +++ /dev/null @@ -1,33 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.verticalscroll.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patches.youtube.misc.fix.verticalscroll.annotations.VerticalScrollCompatibility -import app.revanced.patches.youtube.misc.fix.verticalscroll.fingerprints.CanScrollVerticallyFingerprint - -@Description("Fixes issues with scrolling on the home screen when the first component is of type EmptyComponent.") -@VerticalScrollCompatibility -@Version("0.0.1") -class VerticalScrollPatch : BytecodePatch( - listOf(CanScrollVerticallyFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - val result = CanScrollVerticallyFingerprint.result ?: return CanScrollVerticallyFingerprint.toErrorResult() - - result.mutableMethod.addInstructions( - 0, - """ - const/4 v0, 0x0 - return v0 - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/patch/PremiumHeadingPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/forceheader/PremiumHeadingPatch.kt similarity index 60% rename from src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/patch/PremiumHeadingPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/forceheader/PremiumHeadingPatch.kt index 83eca468f..812a558fd 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/branding/header/patch/PremiumHeadingPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/forceheader/PremiumHeadingPatch.kt @@ -1,26 +1,27 @@ -package app.revanced.patches.youtube.layout.branding.header.patch +package app.revanced.patches.youtube.misc.forceheader.patch import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.layout.branding.header.annotations.PremiumHeadingCompatibility -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper import java.nio.file.Files import java.nio.file.StandardCopyOption import kotlin.io.path.exists -@Patch -@DependsOn([FixLocaleConfigErrorPatch::class]) -@Name("premium-heading") -@Description("Shows premium branding on the home screen.") -@PremiumHeadingCompatibility +@Patch(false) +@Name("force-premium-heading") +@Description("Forces premium heading on the home screen.") +@DependsOn([SettingsPatch::class]) +@YouTubeCompatibility @Version("0.0.1") class PremiumHeadingPatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { @@ -46,6 +47,23 @@ class PremiumHeadingPatch : ResourcePatch { } } + val revancedprefs = context["res/xml/revanced_prefs.xml"] + revancedprefs.writeText( + revancedprefs.readText() + .replace( + "", + "" + ).replace( + "header-switch", + "force-premium-heading" + ) + ) + + ResourceHelper.patchSuccess( + context, + "force-premium-heading" + ) + return PatchResultSuccess() } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt deleted file mode 100644 index 36872698f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/annotations/HDRBrightnessCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.hdrbrightness.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class HDRBrightnessCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/bytecode/fingerprints/HDRBrightnessFingerprint.kt similarity index 78% rename from src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/bytecode/fingerprints/HDRBrightnessFingerprint.kt index 979f4e8a5..8985c6ca2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/fingerprints/HDRBrightnessFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/bytecode/fingerprints/HDRBrightnessFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.hdrbrightness.fingerprints +package app.revanced.patches.youtube.misc.hdrbrightness.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/bytecode/patch/HDRBrightnessBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/bytecode/patch/HDRBrightnessBytecodePatch.kt new file mode 100644 index 000000000..008089228 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/bytecode/patch/HDRBrightnessBytecodePatch.kt @@ -0,0 +1,51 @@ +package app.revanced.patches.youtube.misc.hdrbrightness.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.hdrbrightness.bytecode.fingerprints.HDRBrightnessFingerprint +import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.MISC_PATH +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction +import org.jf.dexlib2.iface.reference.FieldReference + +@Name("enable-hdr-auto-brightness-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.2") +@DependsOn([LegacyVideoIdPatch::class]) +class HDRBrightnessBytecodePatch : BytecodePatch( + listOf(HDRBrightnessFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + val result = HDRBrightnessFingerprint.result!! + val method = result.mutableMethod + + method.implementation!!.instructions.filter { instruction -> + val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference + fieldReference?.let { it.name == "screenBrightness" } == true + }.forEach { instruction -> + val brightnessRegisterIndex = method.implementation!!.instructions.indexOf(instruction) + val register = (instruction as TwoRegisterInstruction).registerA + + val insertIndex = brightnessRegisterIndex + 1 + method.addInstructions( + insertIndex, + """ + invoke-static {v$register}, $MISC_PATH/HDRAutoBrightnessPatch;->getHDRBrightness(F)F + move-result v$register + """ + ) + } + + LegacyVideoIdPatch.injectCall("$MISC_PATH/HDRAutoBrightnessPatch;->newVideoStarted(Ljava/lang/String;)V") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt deleted file mode 100644 index f84efbee9..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/patch/HDRBrightnessPatch.kt +++ /dev/null @@ -1,64 +0,0 @@ -package app.revanced.patches.youtube.misc.hdrbrightness.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.hdrbrightness.annotations.HDRBrightnessCompatibility -import app.revanced.patches.youtube.misc.hdrbrightness.fingerprints.HDRBrightnessFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction -import org.jf.dexlib2.iface.reference.FieldReference - -@Patch -@Name("hdr-auto-brightness") -@Description("Makes the brightness of HDR videos follow the system default.") -@HDRBrightnessCompatibility -@Version("0.0.2") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -class HDRBrightnessPatch : BytecodePatch( - listOf(HDRBrightnessFingerprint) -) { - override fun execute(context: BytecodeContext): 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 = HDRBrightnessFingerprint.result!!.mutableMethod - - method.implementation!!.instructions.filter { instruction -> - val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference - fieldReference?.let { it.name == "screenBrightness" } == true - }.forEach { instruction -> - val brightnessRegisterIndex = method.implementation!!.instructions.indexOf(instruction) - val register = (instruction as TwoRegisterInstruction).registerA - - val insertIndex = brightnessRegisterIndex + 1 - method.addInstructions( - insertIndex, - """ - invoke-static {v$register}, Lapp/revanced/integrations/patches/HDRAutoBrightnessPatch;->getHDRBrightness(F)F - move-result v$register - """ - ) - } - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/resource/patch/HDRBrightnessPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/resource/patch/HDRBrightnessPatch.kt new file mode 100644 index 000000000..7893c25a5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/hdrbrightness/resource/patch/HDRBrightnessPatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.misc.hdrbrightness.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.hdrbrightness.bytecode.patch.HDRBrightnessBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-hdr-auto-brightness") +@Description("Makes the brightness of HDR videos follow the system default.") +@DependsOn( + [ + HDRBrightnessBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class HDRBrightnessPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: MISC_SETTINGS", + "SETTINGS: ENABLE_HDR_AUTO_BRIGHTNESS" + ) + + ResourceHelper.patchSuccess( + context, + "enable-hdr-auto-brightness" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt deleted file mode 100644 index d8e9cd76e..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/annotations/IntegrationsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.integrations.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class IntegrationsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt index 730e856c1..2f48bd871 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/InitFingerprint.kt @@ -1,6 +1,6 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint object InitFingerprint : IntegrationsFingerprint( strings = listOf("Application creation"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt index 813aaf573..72fddf9c4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/ServiceFingerprint.kt @@ -1,6 +1,6 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint object ServiceFingerprint : IntegrationsFingerprint( customFingerprint = { methodDef -> methodDef.definingClass.endsWith("ApiPlayerService;") && methodDef.name == "" }, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerFingerprint.kt index ff7106145..459460496 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/fingerprints/StandalonePlayerFingerprint.kt @@ -1,6 +1,6 @@ package app.revanced.patches.youtube.misc.integrations.fingerprints -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch.IntegrationsFingerprint +import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch.IntegrationsFingerprint object StandalonePlayerFingerprint : IntegrationsFingerprint( strings = listOf( diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt index a5d219fa3..2aa2fe93d 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/integrations/patch/IntegrationsPatch.kt @@ -1,15 +1,15 @@ package app.revanced.patches.youtube.misc.integrations.patch import app.revanced.patcher.annotation.Name -import app.revanced.patches.youtube.misc.integrations.annotations.IntegrationsCompatibility import app.revanced.patches.youtube.misc.integrations.fingerprints.InitFingerprint import app.revanced.patches.youtube.misc.integrations.fingerprints.ServiceFingerprint import app.revanced.patches.youtube.misc.integrations.fingerprints.StandalonePlayerFingerprint -import app.revanced.patches.shared.integrations.patch.AbstractIntegrationsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.integrations.AbstractIntegrationsPatch @Name("integrations") -@IntegrationsCompatibility +@YouTubeCompatibility class IntegrationsPatch : AbstractIntegrationsPatch( "Lapp/revanced/integrations/utils/ReVancedUtils;", - listOf(InitFingerprint, StandalonePlayerFingerprint, ServiceFingerprint), + listOf(InitFingerprint), ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt deleted file mode 100644 index ea1772ec6..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/annotation/LithoFilterCompatibility.kt +++ /dev/null @@ -1,14 +0,0 @@ -package app.revanced.patches.youtube.misc.litho.filter.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class LithoFilterCompatibility - diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/LithoFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/LithoFingerprint.kt new file mode 100644 index 000000000..7edbdd432 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/fingerprints/LithoFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.patches.youtube.misc.litho.filter.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction + +object LithoFingerprint : MethodFingerprint( + "L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L", "L", "L", "L", "I", "Z"), + customFingerprint = { methodDef -> + methodDef.implementation!!.instructions.any { + ((it as? NarrowLiteralInstruction)?.narrowLiteral == 255496645) + } + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt index 9ea24e433..edb1df8f3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/litho/filter/patch/LithoFilterPatch.kt @@ -1,81 +1,81 @@ package app.revanced.patches.youtube.misc.litho.filter.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.litho.filter.annotation.LithoFilterCompatibility -import app.revanced.patches.youtube.misc.litho.filter.fingerprints.ComponentContextParserFingerprint -import app.revanced.patches.youtube.misc.litho.filter.fingerprints.EmptyComponentBuilderFingerprint -import org.jf.dexlib2.iface.instruction.Instruction -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import app.revanced.patches.youtube.misc.doublebacktoexit.patch.DoubleBackToExitPatch +import app.revanced.patches.youtube.misc.litho.filter.fingerprints.LithoFingerprint +import app.revanced.patches.youtube.misc.swiperefresh.patch.SwipeRefreshPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.ADS_PATH +import org.jf.dexlib2.builder.instruction.BuilderInstruction21c import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import org.jf.dexlib2.iface.reference.FieldReference import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.Opcode -@DependsOn([IntegrationsPatch::class]) -@Description("Hooks the method which parses the bytes into a ComponentContext to filter components.") -@LithoFilterCompatibility +@DependsOn( + [ + DoubleBackToExitPatch::class, + SwipeRefreshPatch::class + ] +) +@YouTubeCompatibility @Version("0.0.1") class LithoFilterPatch : BytecodePatch( - listOf(ComponentContextParserFingerprint) -) { + listOf( + LithoFingerprint + ) +) +{ override fun execute(context: BytecodeContext): PatchResult { - ComponentContextParserFingerprint.result?.let { result -> - val builderMethodIndex = EmptyComponentBuilderFingerprint - .also { it.resolve(context, result.mutableMethod, result.mutableClass) } - .let { it.result!!.scanResult.patternScanResult!!.startIndex } - val emptyComponentFieldIndex = builderMethodIndex + 2 + //Litho + val lithoMethod = LithoFingerprint.result!!.mutableMethod + val lithoMethodThirdParam = lithoMethod.parameters[2] + val lithoRegister1 = lithoMethod.implementation!!.registerCount - lithoMethod.parameters.size + 1 + val lithoRegister2 = lithoRegister1 + 1 + val lithoInstructions = lithoMethod.implementation!!.instructions - with(result.mutableMethod) { - val insertHookIndex = result.scanResult.patternScanResult!!.endIndex - val clobberedRegister = (instruction(insertHookIndex - 3) as OneRegisterInstruction).registerA + val lithoIndex = lithoInstructions.indexOfFirst { + it.opcode == Opcode.CONST_STRING && + (it as BuilderInstruction21c).reference.toString() == "Element missing type extension" + } + 2 - val builderMethodDescriptor = instruction(builderMethodIndex).toDescriptor() - val emptyComponentFieldDescriptor = instruction(emptyComponentFieldIndex).toDescriptor() - - val stringBuilderRegister = (instruction(insertHookIndex - 1) as TwoRegisterInstruction).registerA - - addInstructions( - insertHookIndex, // right after setting the component.pathBuilder field, - """ - invoke-static {v$stringBuilderRegister, v0}, Lapp/revanced/integrations/patches/LithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z - move-result v$clobberedRegister - if-eqz v$clobberedRegister, :not_an_ad - move-object/from16 v0, p1 - invoke-static {v0}, $builderMethodDescriptor - move-result-object v0 - iget-object v0, v0, $emptyComponentFieldDescriptor - return-object v0 - """, - listOf(ExternalLabel("not_an_ad", instruction(insertHookIndex))) - ) + val FirstReference = + lithoMethod.let { method -> + (method.implementation!!.instructions.elementAt(lithoIndex) as ReferenceInstruction).reference as MethodReference } - } ?: return PatchResultError("Could not find the method to hook.") + + val SecondReference = + lithoMethod.let { method -> + (method.implementation!!.instructions.elementAt(lithoIndex + 2) as ReferenceInstruction).reference as FieldReference + } + + lithoMethod.addInstructions( + 0, """ + move-object/from16 v1, v$lithoRegister1 + invoke-virtual {v1}, Ljava/lang/Object;->toString()Ljava/lang/String; + move-result-object v1 + move-object/from16 v2, v$lithoRegister2 + iget-object v2, v2, $lithoMethodThirdParam->b:Ljava/nio/ByteBuffer; + invoke-static {v1, v2}, $ADS_PATH/ExtendedLithoFilterPatch;->InflatedLithoView(Ljava/lang/String;Ljava/nio/ByteBuffer;)Z + move-result v3 + if-eqz v3, :do_not_block + move-object/from16 v0, p1 + invoke-static {v0}, $FirstReference + move-result-object v0 + iget-object v0, v0, ${SecondReference.definingClass}->${SecondReference.name}:${SecondReference.type} + return-object v0 + """, listOf(ExternalLabel("do_not_block", lithoMethod.instruction(0))) + ) return PatchResultSuccess() } - - private companion object { - fun Instruction.toDescriptor() = when (val reference = (this as? ReferenceInstruction)?.reference) { - is MethodReference -> "${reference.definingClass}->${reference.name}(${ - reference.parameterTypes.joinToString( - "" - ) { it } - })${reference.returnType}" - is FieldReference -> "${reference.definingClass}->${reference.name}:${reference.type}" - else -> throw PatchResultError("Unsupported reference type") - } - } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/annotations/FixLocaleConfigErrorCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/annotations/FixLocaleConfigErrorCompatibility.kt deleted file mode 100644 index a304b71f0..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/annotations/FixLocaleConfigErrorCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.manifest.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class FixLocaleConfigErrorCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt index 801e444d3..a6520fd57 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/manifest/patch/FixLocaleConfigErrorPatch.kt @@ -7,12 +7,12 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patches.youtube.misc.manifest.annotations.FixLocaleConfigErrorCompatibility +import app.revanced.shared.annotation.YouTubeCompatibility import org.w3c.dom.Element @Name("locale-config-fix") @Description("Fixes an error when building the resources by patching the manifest file.") -@FixLocaleConfigErrorCompatibility +@YouTubeCompatibility @Version("0.0.1") class FixLocaleConfigErrorPatch : ResourcePatch { override fun execute(context: ResourceContext): PatchResult { @@ -28,7 +28,8 @@ class FixLocaleConfigErrorPatch : ResourcePatch { // by replacing the attributes name val attribute = "android:localeConfig" applicationNode.setAttribute("localeConfig", applicationNode.getAttribute(attribute)) - applicationNode.removeAttribute(attribute) + applicationNode.removeAttribute("android:localeConfig") + } return PatchResultSuccess() diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/materialyou/patch/MaterialYouPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/materialyou/patch/MaterialYouPatch.kt new file mode 100644 index 000000000..3c069d2a6 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/materialyou/patch/MaterialYouPatch.kt @@ -0,0 +1,80 @@ +package app.revanced.patches.youtube.misc.materialyou.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.theme.bytecode.GeneralThemePatch +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch(false) +@Name("materialyou") +@Description("Enables MaterialYou theme for Android 12+") +@DependsOn( + [ + GeneralThemePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class MaterialYouPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + val drawables1 = "drawable-night-v31" to arrayOf( + "new_content_dot_background.xml" + ) + + val drawables2 = "drawable-v31" to arrayOf( + "new_content_count_background.xml", + "new_content_dot_background.xml" + ) + + val layout1 = "layout-v31" to arrayOf( + "new_content_count.xml" + ) + + arrayOf(drawables1, drawables2, layout1).forEach { (path, resourceNames) -> + Files.createDirectory(context["res"].resolve("$path").toPath()) + resourceNames.forEach { name -> + val monetPath = "$path/$name" + + Files.copy( + this.javaClass.classLoader.getResourceAsStream("youtube/materialyou/$monetPath")!!, + context["res"].resolve(monetPath).toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + val sourcePath = this.javaClass.classLoader.getResourceAsStream("youtube/materialyou/host/values-v31/colors.xml")!! + val relativePath = context.xmlEditor["res/values-v31/colors.xml"] + + "resources".copyXmlNode( + context.xmlEditor[sourcePath], + relativePath + ).also {}.close() + + /* + add settings + */ + + ResourceHelper.themePatchSuccess( + context, + "default", + "materialyou" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt deleted file mode 100644 index 4f4fa0d6b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/annotations/MicroGPatchCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.microg.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MicroGPatchCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastContextFetchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastContextFetchFingerprint.kt similarity index 71% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastContextFetchFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastContextFetchFingerprint.kt index 577f1016a..56e84979e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastContextFetchFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastContextFetchFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints - +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastDynamiteModuleFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastDynamiteModuleFingerprint.kt similarity index 76% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastDynamiteModuleFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastDynamiteModuleFingerprint.kt index bf1f58cbe..ee652df6f 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/CastDynamiteModuleFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastDynamiteModuleFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints - +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastDynamiteModuleV2Fingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastDynamiteModuleV2Fingerprint.kt similarity index 72% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastDynamiteModuleV2Fingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastDynamiteModuleV2Fingerprint.kt index f4119e588..f4645919e 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/CastDynamiteModuleV2Fingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/CastDynamiteModuleV2Fingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.music.misc.microg.fingerprints - +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/GooglePlayUtilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/GooglePlayUtilityFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/GooglePlayUtilityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/GooglePlayUtilityFingerprint.kt index e50f65699..d62f481de 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/GooglePlayUtilityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/GooglePlayUtilityFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/IntegrityCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/IntegrityCheckFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/IntegrityCheckFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/IntegrityCheckFingerprint.kt index f3d41191b..56a595c58 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/IntegrityCheckFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/IntegrityCheckFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/PrimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/PrimeFingerprint.kt similarity index 73% rename from src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/PrimeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/PrimeFingerprint.kt index e1fcc27d4..e29bc088a 100644 --- a/src/main/kotlin/app/revanced/patches/music/misc/microg/fingerprints/PrimeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/PrimeFingerprint.kt @@ -1,8 +1,7 @@ -package app.revanced.patches.music.misc.microg.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object PrimeFingerprint : MethodFingerprint( - strings = listOf("com.google.android.GoogleCamera", "com.android.vending") +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object PrimeFingerprint : MethodFingerprint( + strings = listOf("com.google.android.GoogleCamera", "com.android.vending") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/ServiceCheckFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/ServiceCheckFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/ServiceCheckFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/ServiceCheckFingerprint.kt index 9a07e2546..71c402592 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/fingerprints/ServiceCheckFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/fingerprints/ServiceCheckFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.microg.fingerprints +package app.revanced.patches.youtube.misc.microg.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/patch/MicroGBytecodePatch.kt similarity index 55% rename from src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/patch/MicroGBytecodePatch.kt index f4869c73d..a5eb619d8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/bytecode/MicroGBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/bytecode/patch/MicroGBytecodePatch.kt @@ -1,61 +1,59 @@ -package app.revanced.patches.youtube.misc.microg.patch.bytecode +package app.revanced.patches.youtube.misc.microg.bytecode.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.fingerprints.WatchWhileActivityFingerprint -import app.revanced.patches.youtube.layout.castbutton.patch.HideCastButtonPatch -import app.revanced.patches.youtube.misc.fix.spoof.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 +import app.revanced.patches.youtube.layout.player.castbutton.resource.patch.HideCastButtonPatch +import app.revanced.patches.youtube.misc.clientspoof.resource.patch.ClientSpoofPatch +import app.revanced.patches.youtube.misc.microg.bytecode.fingerprints.* import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME -import app.revanced.util.microg.MicroGBytecodeHelper +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.bytecode.BytecodeHelper +import app.revanced.shared.util.microg.MicroGBytecodeHelper -@Patch +@Name("microg-support-bytecode-patch") @DependsOn( [ - MicroGResourcePatch::class, + ClientSpoofPatch::class, HideCastButtonPatch::class, - ClientSpoofPatch::class + PatchOptions::class ] ) -@Name("microg-support") -@Description("Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.") -@MicroGPatchCompatibility +@YouTubeCompatibility @Version("0.0.1") class MicroGBytecodePatch : BytecodePatch( listOf( - IntegrityCheckFingerprint, - ServiceCheckFingerprint, - GooglePlayUtilityFingerprint, + CastContextFetchFingerprint, CastDynamiteModuleFingerprint, CastDynamiteModuleV2Fingerprint, - CastContextFetchFingerprint, + GooglePlayUtilityFingerprint, + IntegrityCheckFingerprint, PrimeFingerprint, - WatchWhileActivityFingerprint + ServiceCheckFingerprint ) ) { override fun execute(context: BytecodeContext): PatchResult { + + var packageName = PatchOptions.YouTube_PackageName + // apply common microG patch MicroGBytecodeHelper.patchBytecode( context, arrayOf( MicroGBytecodeHelper.packageNameTransform( PACKAGE_NAME, - REVANCED_PACKAGE_NAME + "$packageName" ) ), MicroGBytecodeHelper.PrimeMethodTransformationData( PrimeFingerprint, PACKAGE_NAME, - REVANCED_PACKAGE_NAME + "$packageName" ), listOf( IntegrityCheckFingerprint, @@ -67,8 +65,7 @@ class MicroGBytecodePatch : BytecodePatch( ) ) - // inject the notice for MicroG - MicroGBytecodeHelper.injectNotice(WatchWhileActivityFingerprint) + BytecodeHelper.injectInit(context, "MicroGPatch", "checkAvailability") return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt deleted file mode 100644 index 1cdc47f49..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/patch/resource/MicroGResourcePatch.kt +++ /dev/null @@ -1,62 +0,0 @@ -package app.revanced.patches.youtube.misc.microg.patch.resource - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import app.revanced.patches.youtube.misc.microg.annotations.MicroGPatchCompatibility -import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_APP_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants.REVANCED_PACKAGE_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants.SPOOFED_PACKAGE_NAME -import app.revanced.patches.youtube.misc.microg.shared.Constants.SPOOFED_PACKAGE_SIGNATURE -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch -import app.revanced.util.microg.Constants.MICROG_VENDOR -import app.revanced.util.microg.MicroGManifestHelper -import app.revanced.util.microg.MicroGResourceHelper - -@Name("microg-resource-patch") -@DependsOn([FixLocaleConfigErrorPatch::class, SettingsResourcePatch::class]) -@Description("Resource patch to allow YouTube ReVanced to run without root and under a different package name.") -@MicroGPatchCompatibility -@Version("0.0.1") -class MicroGResourcePatch : ResourcePatch { - override fun execute(context: ResourceContext): PatchResult { - SettingsPatch.addPreference( - Preference( - StringResource("microg_settings", "MicroG Settings"), - Preference.Intent("$MICROG_VENDOR.android.gms", "", "org.microg.gms.ui.SettingsActivity"), - StringResource("microg_settings_summary", "Settings for MicroG"), - ) - ) - SettingsPatch.renameIntentsTargetPackage(REVANCED_PACKAGE_NAME) - - // update manifest - MicroGResourceHelper.patchManifest( - context, - PACKAGE_NAME, - REVANCED_PACKAGE_NAME, - REVANCED_APP_NAME - ) - - // add metadata to manifest - MicroGManifestHelper.addSpoofingMetadata( - context, - SPOOFED_PACKAGE_NAME, - SPOOFED_PACKAGE_SIGNATURE - ) - - // add strings - MicroGResourceHelper.addStrings(context) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/resource/patch/MicroGPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/resource/patch/MicroGPatch.kt new file mode 100644 index 000000000..f87d640b0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/resource/patch/MicroGPatch.kt @@ -0,0 +1,79 @@ +package app.revanced.patches.youtube.misc.microg.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.microg.bytecode.patch.MicroGBytecodePatch +import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME +import app.revanced.patches.youtube.misc.microg.shared.Constants.SPOOFED_PACKAGE_NAME +import app.revanced.patches.youtube.misc.microg.shared.Constants.SPOOFED_PACKAGE_SIGNATURE +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.microg.Constants.MICROG_VENDOR +import app.revanced.shared.util.microg.MicroGManifestHelper +import app.revanced.shared.util.microg.MicroGResourceHelper +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("microg-support") +@Description("Allows YouTube ReVanced to run without root and under a different package name with Vanced MicroG.") +@DependsOn( + [ + SettingsPatch::class, + MicroGBytecodePatch::class, + PatchOptions::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class MicroGPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + var packageName = PatchOptions.YouTube_PackageName + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: MICROG_SETTINGS", + "PREFERENCE: MICROG_SETTINGS", + "SETTINGS: MICROG_SETTINGS" + ) + + ResourceHelper.patchSuccess( + context, + "microg-support" + ) + + val settingsFragment = context["res/xml/settings_fragment.xml"] + settingsFragment.writeText( + settingsFragment.readText().replace( + "android:targetPackage=\"com.google.android.youtube", + "android:targetPackage=\"$packageName" + ) + ) + + // update manifest + MicroGResourceHelper.patchManifest( + context, + PACKAGE_NAME, + "$packageName" + ) + + // add metadata to manifest + MicroGManifestHelper.addSpoofingMetadata( + context, + SPOOFED_PACKAGE_NAME, + SPOOFED_PACKAGE_SIGNATURE + ) + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/shared/Constants.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/shared/Constants.kt index 84b48de2e..5545799f2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/microg/shared/Constants.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/microg/shared/Constants.kt @@ -1,8 +1,6 @@ package app.revanced.patches.youtube.misc.microg.shared object Constants { - internal const val REVANCED_APP_NAME = "YouTube ReVanced" - internal const val REVANCED_PACKAGE_NAME = "app.revanced.android.youtube" internal const val PACKAGE_NAME = "com.google.android.youtube" internal const val SPOOFED_PACKAGE_NAME = PACKAGE_NAME internal const val SPOOFED_PACKAGE_SIGNATURE = "24bb24c05e47e0aefa68a58a766179d9b613a600" diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt deleted file mode 100644 index c64a1be83..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/annotations/MinimizedPlaybackCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.minimizedplayback.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class MinimizedPlaybackCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackKidsFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackKidsFingerprint.kt index 860925e5c..694576756 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackKidsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackKidsFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints +package app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackManagerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackManagerFingerprint.kt new file mode 100644 index 000000000..3d0958b57 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackManagerFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction + +object MinimizedPlaybackManagerFingerprint : MethodFingerprint( + "Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), + listOf(Opcode.AND_INT_LIT16), + customFingerprint = { methodDef -> + methodDef.implementation!!.instructions.any { + ((it as? NarrowLiteralInstruction)?.narrowLiteral == 64657230) + } + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackSettingsFingerprint.kt similarity index 89% rename from src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackSettingsFingerprint.kt index af3840d08..f6665d5b9 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackSettingsFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/fingerprints/MinimizedPlaybackSettingsFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints +package app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -6,7 +6,6 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode - @FuzzyPatternScanMethod(2) object MinimizedPlaybackSettingsFingerprint : MethodFingerprint( "L", diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/patch/MinimizedPlaybackBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/patch/MinimizedPlaybackBytecodePatch.kt new file mode 100644 index 000000000..be65f7ba3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/bytecode/patch/MinimizedPlaybackBytecodePatch.kt @@ -0,0 +1,91 @@ +package app.revanced.patches.youtube.misc.minimizedplayback.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.MISC_PATH +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.MethodReference + +@Name("enable-minimized-playback-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class MinimizedPlaybackBytecodePatch : BytecodePatch( + listOf( + MinimizedPlaybackKidsFingerprint, + MinimizedPlaybackManagerFingerprint, + MinimizedPlaybackSettingsFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val methods = arrayOf( + MinimizedPlaybackKidsFingerprint, + MinimizedPlaybackManagerFingerprint, + MinimizedPlaybackSettingsFingerprint + ).map { + it.result!!.mutableMethod + } + + hookPlaybackController(methods[0]) + hookPlayback(methods[1]) + walkMutable(context, methods[2]) + + return PatchResultSuccess() + } + + private companion object { + const val INTEGRATIONS_PLAYBACK_METHOD_REFERENCE = + "$MISC_PATH/MinimizedPlaybackPatch;->enableMinimizedPlayback()Z" + + fun walkMutable( + context: BytecodeContext, + insertMethod: MutableMethod + ) { + val booleanCalls = insertMethod.implementation!!.instructions.withIndex() + .filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" } + + val booleanIndex = booleanCalls.elementAt(1).index + val booleanMethod = + context.toMethodWalker(insertMethod) + .nextMethod(booleanIndex, true) + .getMethod() as MutableMethod + + hookPlayback(booleanMethod) + } + + fun hookPlayback( + insertMethod: MutableMethod + ) { + insertMethod.addInstructions( + 0, """ + invoke-static {}, $INTEGRATIONS_PLAYBACK_METHOD_REFERENCE + move-result v0 + return v0 + """ + ) + } + + fun hookPlaybackController( + insertMethod: MutableMethod + ) { + insertMethod.addInstructions( + 0, """ + invoke-static {}, $INTEGRATIONS_PLAYBACK_METHOD_REFERENCE + move-result v0 + if-eqz v0, :default + return-void + """, listOf(ExternalLabel("default", insertMethod.instruction(0))) + ) + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt deleted file mode 100644 index 015736b73..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/fingerprints/MinimizedPlaybackManagerFingerprint.kt +++ /dev/null @@ -1,42 +0,0 @@ -package app.revanced.patches.youtube.misc.minimizedplayback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - - -@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value. -object MinimizedPlaybackManagerFingerprint : MethodFingerprint( - "Z", - AccessFlags.PUBLIC or AccessFlags.STATIC, - listOf("L"), - listOf( - Opcode.CONST_4, - Opcode.IF_EQZ, - Opcode.IGET, - Opcode.AND_INT_LIT16, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, - Opcode.IF_NEZ, - Opcode.SGET_OBJECT, - Opcode.IGET, - Opcode.CONST, - Opcode.IF_NE, - Opcode.IGET_OBJECT, - Opcode.IF_NEZ, - Opcode.SGET_OBJECT, - Opcode.IGET, - Opcode.IF_NE, - Opcode.IGET_OBJECT, - Opcode.CHECK_CAST, - Opcode.GOTO, - Opcode.SGET_OBJECT, - Opcode.GOTO, - Opcode.CONST_4, - Opcode.IF_EQZ, - Opcode.IGET_BOOLEAN, - Opcode.IF_EQZ - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt deleted file mode 100644 index 94e992464..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/patch/MinimizedPlaybackPatch.kt +++ /dev/null @@ -1,88 +0,0 @@ -package app.revanced.patches.youtube.misc.minimizedplayback.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -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.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.MethodReference - - -@Patch -@Name("minimized-playback") -@Description("Enables minimized and background playback.") -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@MinimizedPlaybackCompatibility -@Version("0.0.1") -class MinimizedPlaybackPatch : BytecodePatch( - listOf( - MinimizedPlaybackKidsFingerprint, MinimizedPlaybackManagerFingerprint, MinimizedPlaybackSettingsFingerprint - ) -) { - override fun execute(context: BytecodeContext): 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( - 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/MinimizedPlaybackPatch;->isMinimizedPlaybackEnabled()Z - move-result v0 - return v0 - """ - ) - - val method = MinimizedPlaybackSettingsFingerprint.result!!.mutableMethod - val booleanCalls = method.implementation!!.instructions.withIndex() - .filter { ((it.value as? ReferenceInstruction)?.reference as? MethodReference)?.returnType == "Z" } - - val settingsBooleanIndex = booleanCalls.elementAt(1).index - val settingsBooleanMethod = - context.toMethodWalker(method).nextMethod(settingsBooleanIndex, true).getMethod() as MutableMethod - - settingsBooleanMethod.addInstructions( - 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/MinimizedPlaybackPatch;->isMinimizedPlaybackEnabled()Z - move-result v0 - return v0 - """ - ) - - MinimizedPlaybackKidsFingerprint.result!!.mutableMethod.addInstructions( - 0, """ - invoke-static {}, Lapp/revanced/integrations/patches/MinimizedPlaybackPatch;->isMinimizedPlaybackEnabled()Z - move-result v0 - if-eqz v0, :enable - return-void - :enable - nop - """ - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/resource/patch/MinimizedPlaybackPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/resource/patch/MinimizedPlaybackPatch.kt new file mode 100644 index 000000000..4139f60e0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/minimizedplayback/resource/patch/MinimizedPlaybackPatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.misc.minimizedplayback.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.minimizedplayback.bytecode.patch.MinimizedPlaybackBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-minimized-playback") +@Description("Enables minimized and background playback.") +@DependsOn( + [ + MinimizedPlaybackBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class MinimizedPlaybackPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: MISC_SETTINGS", + "SETTINGS: ENABLE_MINIMIZED_PLAYBACK" + ) + + ResourceHelper.patchSuccess( + context, + "enable-minimized-playback" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt deleted file mode 100644 index 20241f327..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/annotations/OpenLinksDirectlyCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.openlinksdirectly.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class OpenLinksDirectlyCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt new file mode 100644 index 000000000..c78cd823f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint( + "Ljava/lang/Object", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( + Opcode.CHECK_CAST, + Opcode.INVOKE_STATIC, + Opcode.MOVE_RESULT_OBJECT, + Opcode.RETURN_OBJECT, + Opcode.CHECK_CAST, + Opcode.SGET + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt similarity index 64% rename from src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt index 2dda99b45..b25356e0e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/fingerprints/OpenLinksDirectlyFingerprintSecondary.kt @@ -1,16 +1,10 @@ -package app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints +package app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.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.patches.youtube.misc.openlinksdirectly.annotations.OpenLinksDirectlyCompatibility import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -@Name("open-links-directly-secondary-fingerprint") -@OpenLinksDirectlyCompatibility -@Version("0.0.1") object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint( "L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( Opcode.INVOKE_STATIC, @@ -25,4 +19,4 @@ object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint( Opcode.CONST_STRING ), strings = listOf("Uri must have an absolute scheme") -) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/patch/OpenLinksDirectlyBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/patch/OpenLinksDirectlyBytecodePatch.kt new file mode 100644 index 000000000..646ef5225 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/bytecode/patch/OpenLinksDirectlyBytecodePatch.kt @@ -0,0 +1,55 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.MISC_PATH +import org.jf.dexlib2.iface.instruction.formats.Instruction11x +import org.jf.dexlib2.iface.instruction.formats.Instruction35c +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("enable-open-links-directly-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class OpenLinksDirectlyBytecodePatch : BytecodePatch( + listOf( + OpenLinksDirectlyFingerprintPrimary, + OpenLinksDirectlyFingerprintSecondary + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + OpenLinksDirectlyFingerprintPrimary.hookUriParser(true) + OpenLinksDirectlyFingerprintSecondary.hookUriParser(false) + + return PatchResultSuccess() + } +} + +fun MethodFingerprint.hookUriParser(isPrimaryFingerprint: Boolean) { + fun getTargetRegister(instruction: Instruction): Int { + if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC + return (instruction as Instruction11x).registerA + } + with(this.result!!) { + val startIndex = scanResult.patternScanResult!!.startIndex + val instruction = method.implementation!!.instructions.elementAt(startIndex + 1) + val insertIndex = if (isPrimaryFingerprint) 1 else 2 + val targetRegister = getTargetRegister(instruction) + + mutableMethod.addInstructions( + startIndex + insertIndex, """ + invoke-static {v$targetRegister}, $MISC_PATH/OpenLinksDirectlyPatch;->enableBypassRedirect(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$targetRegister + """ + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt deleted file mode 100644 index e5c497f74..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/fingerprints/OpenLinksDirectlyFingerprintPrimary.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.youtube.misc.openlinksdirectly.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.patches.youtube.misc.openlinksdirectly.annotations.OpenLinksDirectlyCompatibility -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -@Name("open-links-directly-primary-fingerprint") -@OpenLinksDirectlyCompatibility -@Version("0.0.1") -object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint( - "L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( - Opcode.CHECK_CAST, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.RETURN_OBJECT, - Opcode.CHECK_CAST, - Opcode.SGET - ) -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/patch/OpenLinksDirectlyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/patch/OpenLinksDirectlyPatch.kt deleted file mode 100644 index fc4fb510d..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/patch/OpenLinksDirectlyPatch.kt +++ /dev/null @@ -1,72 +0,0 @@ -package app.revanced.patches.youtube.misc.openlinksdirectly.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -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.BytecodePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.openlinksdirectly.annotations.OpenLinksDirectlyCompatibility -import app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints.OpenLinksDirectlyFingerprintPrimary -import app.revanced.patches.youtube.misc.openlinksdirectly.fingerprints.OpenLinksDirectlyFingerprintSecondary -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import org.jf.dexlib2.iface.instruction.Instruction -import org.jf.dexlib2.iface.instruction.formats.Instruction11x -import org.jf.dexlib2.iface.instruction.formats.Instruction35c - -@Patch -@DependsOn([IntegrationsPatch::class, SettingsPatch::class]) -@Name("open-links-directly") -@Description("Bypasses URL redirects and opens links directly inside YouTube app.") -@OpenLinksDirectlyCompatibility -@Version("0.0.1") -class OpenLinksDirectlyPatch : BytecodePatch( - listOf( - OpenLinksDirectlyFingerprintPrimary, OpenLinksDirectlyFingerprintSecondary - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_uri_redirect", - StringResource("revanced_uri_redirect_title", "Open YouTube links inside app"), - true, - StringResource("revanced_uri_redirect_summary_on", "Links opened inside YouTube ReVanced"), - StringResource("revanced_uri_redirect_summary_off", "Links opened in web browser") - ) - ) - - OpenLinksDirectlyFingerprintPrimary.hookUriParser(true) - OpenLinksDirectlyFingerprintSecondary.hookUriParser(false) - - return PatchResultSuccess() - } -} - -fun MethodFingerprint.hookUriParser(isPrimaryFingerprint: Boolean) { - fun getTargetRegister(instruction: Instruction): Int { - if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC - return (instruction as Instruction11x).registerA - } - with(this.result!!) { - val startIndex = scanResult.patternScanResult!!.startIndex - val instruction = method.implementation!!.instructions.elementAt(startIndex + 1) - val insertIndex = if (isPrimaryFingerprint) 1 else 2 - val targetRegister = getTargetRegister(instruction) - - mutableMethod.addInstructions( - startIndex + insertIndex, """ - invoke-static {v$targetRegister}, Lapp/revanced/integrations/patches/OpenLinksDirectlyPatch;->parseRedirectUri(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$targetRegister - """ - ) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/resource/patch/OpenLinksDirectlyPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/resource/patch/OpenLinksDirectlyPatch.kt new file mode 100644 index 000000000..076558b36 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/openlinksdirectly/resource/patch/OpenLinksDirectlyPatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.misc.openlinksdirectly.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.patch.OpenLinksDirectlyBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("enable-open-links-directly") +@Description("Bypass URL redirects (youtube.com/redirect) when opening links in video descriptions.") +@DependsOn( + [ + OpenLinksDirectlyBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class OpenLinksDirectlyPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: MISC_SETTINGS", + "SETTINGS: ENABLE_OPEN_LINKS_DIRECTLY" + ) + + ResourceHelper.patchSuccess( + context, + "enable-open-links-directly" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/MissingTranslationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/MissingTranslationPatch.kt new file mode 100644 index 000000000..7e4e58960 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/MissingTranslationPatch.kt @@ -0,0 +1,110 @@ +package app.revanced.patches.youtube.misc.optimize.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode + +@Name("add-missing-transition-patch") +@Description("Adds missing translation files from YouTube.") +@YouTubeCompatibility +@Version("0.0.1") +class MissingTranslationPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + LANGUAGE_LIST.forEach { name -> + context.copyXmlNode("youtube/resource/host", "values-$name/strings.xml", "resources") + } + + return PatchResultSuccess() + } + + private companion object { + val LANGUAGE_LIST = arrayOf( + "af", + "am", + "ar", + "az", + "b+sr+Latn", + "be", + "bg", + "bn", + "bs", + "ca", + "cs", + "da", + "de", + "el", + "en-rGB", + "en-rIN", + "es", + "es-rUS", + "et", + "eu", + "fa", + "fi", + "fr", + "fr-rCA", + "gl", + "gu", + "hi", + "hr", + "hu", + "hy", + "in", + "is", + "it", + "iw", + "ja", + "ka", + "kk", + "km", + "kn", + "ko", + "ky", + "lo", + "lt", + "lv", + "mk", + "ml", + "mn", + "mr", + "ms", + "my", + "nb", + "ne", + "nl", + "pa", + "pl", + "pt-rBR", + "pt-rPT", + "ro", + "ru", + "si", + "sk", + "sl", + "sq", + "sr", + "sv", + "sw", + "ta", + "te", + "th", + "tl", + "tr", + "uk", + "ur", + "uz", + "vi", + "zh-rCN", + "zh-rHK", + "zh-rTW", + "zu" + ) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/OptimizeResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/OptimizeResourcePatch.kt new file mode 100644 index 000000000..50a0ea75e --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/OptimizeResourcePatch.kt @@ -0,0 +1,45 @@ +package app.revanced.patches.youtube.misc.optimize.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.optimize.patch.RedundantResourcePatch +import app.revanced.patches.youtube.misc.optimize.patch.MissingTranslationPatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardCopyOption +import java.util.Comparator + +@Patch +@Name("optimize-resource") +@DependsOn( + [ + RedundantResourcePatch::class, + MissingTranslationPatch::class, + SettingsPatch::class + ] +) +@Description("Removes duplicate resources and adds missing translation files from YouTube.") +@YouTubeCompatibility +@Version("0.0.1") +class OptimizeResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + ResourceHelper.patchSuccess( + context, + "optimize-resource" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/RedundantResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/RedundantResourcePatch.kt new file mode 100644 index 000000000..822aff1c0 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/optimize/patch/RedundantResourcePatch.kt @@ -0,0 +1,193 @@ +package app.revanced.patches.youtube.misc.optimize.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources +import java.io.File +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.StandardCopyOption +import java.util.Comparator + +@Name("remove-duplicate-resource-patch") +@Description("Removes duplicate resources from YouTube.") +@YouTubeCompatibility +@Version("0.0.1") +class RedundantResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + // Convert universal APK to anti-split APK + arrayOf( + WHITELIST_MDPI, + WHITELIST_HDPI, + WHITELIST_XHDPI, + WHITELIST_XXXHDPI + ).forEach { (path, array) -> + val tmpDirectory = "$path" + "-v21" + Files.createDirectory(context["res"].resolve(tmpDirectory).toPath()) + + (WHITELIST_GENERAL + array).forEach { name -> + try { + Files.copy( + context["res"].resolve("$path/$name").toPath(), + context["res"].resolve("$tmpDirectory/$name").toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } catch (e: Exception) {} + } + val directoryPath = context["res"].resolve("$path") + + Files.walk(directoryPath.toPath()) + .map(Path::toFile) + .sorted(Comparator.reverseOrder()) + .forEach(File::delete) + + Files.move( + context["res"].resolve(tmpDirectory).toPath(), + context["res"].resolve(path).toPath() + ) + } + + context.copyResources( + "youtube/resource", + ResourceUtils.ResourceGroup( + "raw", + "third_party_licenses" + ) + ) + + return PatchResultSuccess() + } + + private companion object { + val WHITELIST_GENERAL = arrayOf( + "product_logo_youtube_color_24.png", + "product_logo_youtube_color_36.png", + "product_logo_youtube_color_144.png", + "product_logo_youtube_color_192.png", + "yt_outline_audio_black_24.png", + "yt_outline_bag_black_24.png", + "yt_outline_fashion_black_24.png", + "yt_outline_film_strip_black_24.png", + "yt_outline_fire_black_24.png", + "yt_outline_gaming_black_24.png", + "yt_outline_lightbulb_black_24.png", + "yt_outline_news_black_24.png", + "yt_outline_radar_live_black_24.png", + "yt_outline_trophy_black_24.png", + "yt_premium_wordmark_header_dark.png", + "yt_premium_wordmark_header_light.png" + ) + + val WHITELIST_MDPI = "drawable-mdpi" to arrayOf( + "ic_searchable.webp" + ) + + val WHITELIST_HDPI = "drawable-hdpi" to arrayOf( + "transition.png" + ) + + val WHITELIST_XHDPI = "drawable-xhdpi" to arrayOf( + "action_bar_logo_release.png", + "ad_feed_call_to_action_arrow.webp", + "ad_skip.png", + "alert_error.png", + "api_btn_cc_off.png", + "api_btn_cc_on.png", + "api_btn_hd_off.png", + "api_btn_hd_on.png", + "api_btn_hq_off.png", + "api_btn_hq_on.png", + "api_btn_next.png", + "api_btn_pause.png", + "api_btn_play.png", + "api_btn_prev.png", + "api_btn_replay.png", + "api_btn_unavailable.png", + "api_ic_full_screen.png", + "api_ic_full_screen_selected.png", + "api_ic_live.9.png", + "api_ic_options.png", + "api_ic_options_selected.png", + "api_ic_small_screen.png", + "api_ic_small_screen_selected.png", + "api_player_bar.9.png", + "api_player_buffered.9.png", + "api_player_menu_bar.9.png", + "api_player_track.9.png", + "api_play_on_you_tube.png", + "api_scrubber.png", + "api_scrubber_selected.png", + "box_shadow.9.png", + "btn_play_all.9.png", + "card_frame_bottom.9.png", + "card_frame_middle.9.png", + "circle_shadow.9.png", + "common_full_open_on_phone.png", + "compat_selector_disabled.9.png", + "compat_selector_focused.9.png", + "compat_selector_longpressed.9.png", + "compat_selector_pressed.9.png", + "ic_account_switcher_alert.png", + "ic_annotation_close.png", + "ic_api_youtube_logo.png", + "ic_api_youtube_logo_pressed.png", + "ic_api_youtube_watermark.png", + "ic_notification_error.png", + "ic_notification_error_small.webp", + "ic_playlist_icon.png", + "ic_unavailable_common.webp", + "ic_youtube_logo.png", + "lc_editbox_dropdown_background_dark.9.png", + "star_empty.webp", + "star_filled.webp", + "survey_checked.png", + "survey_unchecked.png", + "textfield_default_mtrl_alpha.9.png", + "youtube_lozenge_logo.png", + "youtube_lozenge_logo_dni.png" + ) + + val WHITELIST_XXXHDPI = "drawable-xxxhdpi" to arrayOf( + "ic_group_collapse_00.png", + "ic_group_collapse_01.png", + "ic_group_collapse_02.png", + "ic_group_collapse_03.png", + "ic_group_collapse_04.png", + "ic_group_collapse_05.png", + "ic_group_collapse_06.png", + "ic_group_collapse_07.png", + "ic_group_collapse_08.png", + "ic_group_collapse_09.png", + "ic_group_collapse_10.png", + "ic_group_collapse_11.png", + "ic_group_collapse_12.png", + "ic_group_collapse_13.png", + "ic_group_collapse_14.png", + "ic_group_collapse_15.png", + "ic_group_expand_00.png", + "ic_group_expand_01.png", + "ic_group_expand_02.png", + "ic_group_expand_03.png", + "ic_group_expand_04.png", + "ic_group_expand_05.png", + "ic_group_expand_06.png", + "ic_group_expand_07.png", + "ic_group_expand_08.png", + "ic_group_expand_09.png", + "ic_group_expand_10.png", + "ic_group_expand_11.png", + "ic_group_expand_12.png", + "ic_group_expand_13.png", + "ic_group_expand_14.png", + "ic_group_expand_15.png" + ) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/fingerprints/PrimaryPiPFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/fingerprints/PrimaryPiPFingerprint.kt new file mode 100644 index 000000000..9acfdd2e1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/fingerprints/PrimaryPiPFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.pipnotification.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object PrimaryPiPFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.CHECK_CAST, + Opcode.IGET_OBJECT + ), + strings = listOf("OnYpcTransactionListener") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/fingerprints/SecondaryPiPFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/fingerprints/SecondaryPiPFingerprint.kt new file mode 100644 index 000000000..a19cdedec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/fingerprints/SecondaryPiPFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.pipnotification.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object SecondaryPiPFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL + ), + strings = listOf("honeycomb.Shell\$HomeActivity") +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/patch/PiPNotificationBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/patch/PiPNotificationBytecodePatch.kt new file mode 100644 index 000000000..3dfc78fe8 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/bytecode/patch/PiPNotificationBytecodePatch.kt @@ -0,0 +1,36 @@ +package app.revanced.patches.youtube.misc.pipnotification.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.pipnotification.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.toErrorResult + +@Name("hide-pip-notification-bytecode-patch") +@YouTubeCompatibility +@Version("0.0.1") +class PiPNotificationBytecodePatch : BytecodePatch( + listOf( + PrimaryPiPFingerprint, + SecondaryPiPFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + arrayOf( + PrimaryPiPFingerprint, + SecondaryPiPFingerprint + ).map { + it.result ?: return it.toErrorResult() + }.forEach { result -> + result.mutableMethod.addInstruction(0, "return-void") + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/resource/patch/PiPNotificationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/resource/patch/PiPNotificationPatch.kt new file mode 100644 index 000000000..f821129ec --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/pipnotification/resource/patch/PiPNotificationPatch.kt @@ -0,0 +1,38 @@ +package app.revanced.patches.youtube.misc.pipnotification.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.pipnotification.bytecode.patch.PiPNotificationBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("hide-pip-notification") +@Description("Disable pip notification when you first launch pip mode.") +@DependsOn( + [ + PiPNotificationBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class PiPNotificationPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + ResourceHelper.patchSuccess( + context, + "hide-pip-notification" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playerbuttonoverlay/patch/PlayerButtonOverlayPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playerbuttonoverlay/patch/PlayerButtonOverlayPatch.kt new file mode 100644 index 000000000..bedfd35d2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playerbuttonoverlay/patch/PlayerButtonOverlayPatch.kt @@ -0,0 +1,53 @@ +package app.revanced.patches.youtube.misc.playerbuttonoverlay.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.doRecursively +import app.revanced.shared.util.resources.ResourceHelper +import org.w3c.dom.Element + +@Patch +@Name("remove-player-button-background") +@Description("Removes the background from the video player buttons.") +@DependsOn([SettingsPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class PlayerButtonOverlayPatch : ResourcePatch { + private companion object { + const val RESOURCE_FILE_PATH = "res/drawable/player_button_circle_background.xml" + + val replacements = arrayOf( + "color" + ) + } + + override fun execute(context: ResourceContext): PatchResult { + context.xmlEditor[RESOURCE_FILE_PATH].use { editor -> + editor.file.doRecursively { node -> + replacements.forEach replacement@{ replacement -> + if (node !is Element) return@replacement + + node.getAttributeNode("android:$replacement")?.let { attribute -> + attribute.textContent = "@android:color/transparent" + } + } + } + } + + ResourceHelper.patchSuccess( + context, + "remove-player-button-background" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt deleted file mode 100644 index 9149a05e1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/annotation/PlayerControlsCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.playercontrols.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PlayerControlsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/bytecode/patch/PlayerControlsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/bytecode/patch/PlayerControlsBytecodePatch.kt index 50b3d5cf1..e7a49eead 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/bytecode/patch/PlayerControlsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/bytecode/patch/PlayerControlsBytecodePatch.kt @@ -5,79 +5,87 @@ import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -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 app.revanced.patches.youtube.misc.playercontrols.fingerprints.* +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility import org.jf.dexlib2.iface.instruction.OneRegisterInstruction @Name("player-controls-bytecode-patch") -@DependsOn([ResourceMappingPatch::class]) +@DependsOn([SharedResourcdIdPatch::class]) @Description("Manages the code for the player controls of the YouTube player.") -@PlayerControlsCompatibility +@YouTubeCompatibility @Version("0.0.1") class PlayerControlsBytecodePatch : BytecodePatch( - listOf(PlayerControlsVisibilityFingerprint) + listOf( + BottomControlsInflateFingerprint, + ControlsLayoutInflateFingerprint, + PlayerControlsVisibilityFingerprint, + VisibilityNegatedParentFingerprint + ) ) { override fun execute(context: BytecodeContext): PatchResult { showPlayerControlsFingerprintResult = PlayerControlsVisibilityFingerprint.result!! - - bottomUiContainerResourceId = ResourceMappingPatch - .resourceMappings - .single { it.type == "id" && it.name == "bottom_ui_container_stub" }.id + controlsLayoutInflateFingerprintResult = ControlsLayoutInflateFingerprint.result!! // TODO: another solution is required, this is hacky listOf(BottomControlsInflateFingerprint).resolve(context, context.classes) inflateFingerprintResult = BottomControlsInflateFingerprint.result!! + VisibilityNegatedFingerprint.resolve(context, VisibilityNegatedParentFingerprint.result!!.classDef) + visibilityNegatedFingerprintResult = VisibilityNegatedFingerprint.result!! + return PatchResultSuccess() } internal companion object { - var bottomUiContainerResourceId: Long = 0 - lateinit var showPlayerControlsFingerprintResult: MethodFingerprintResult + lateinit var controlsLayoutInflateFingerprintResult: MethodFingerprintResult + lateinit var inflateFingerprintResult: MethodFingerprintResult + lateinit var visibilityNegatedFingerprintResult: MethodFingerprintResult - private var inflateFingerprintResult: MethodFingerprintResult? = null - set(fingerprint) { - field = fingerprint!!.also { - moveToRegisterInstructionIndex = it.scanResult.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( + fun MethodFingerprintResult.injectVisibilityCall( + descriptor: String, + fieldname: String + ) { + mutableMethod.addInstruction( 0, - """ - invoke-static {p1}, $descriptor - """ + "invoke-static {p1}, $descriptor->$fieldname(Z)V" ) } - /** - * 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" + fun MethodFingerprintResult.injectCalls( + descriptor: String + ) { + val endIndex = scanResult.patternScanResult!!.endIndex + val viewRegister = (mutableMethod.instruction(endIndex) as OneRegisterInstruction).registerA + + mutableMethod.addInstruction( + endIndex + 1, + "invoke-static {v$viewRegister}, $descriptor->initialize(Ljava/lang/Object;)V" ) } + + fun injectVisibility(descriptor: String) { + showPlayerControlsFingerprintResult.injectVisibilityCall("$descriptor", "changeVisibility") + } + + fun injectVisibilityNegated(descriptor: String) { + visibilityNegatedFingerprintResult.injectVisibilityCall("$descriptor", "changeVisibilityNegatedImmediate") + } + + fun initializeSB(descriptor: String) { + controlsLayoutInflateFingerprintResult.injectCalls("$descriptor") + } + + fun initializeControl(descriptor: String) { + inflateFingerprintResult.injectCalls("$descriptor") + } } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt index 9df6bcf0c..3de482da6 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/BottomControlsInflateFingerprint.kt @@ -1,10 +1,9 @@ package app.revanced.patches.youtube.misc.playercontrols.fingerprints - import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode object BottomControlsInflateFingerprint : MethodFingerprint( opcodes = listOf( @@ -15,7 +14,7 @@ object BottomControlsInflateFingerprint : MethodFingerprint( customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == PlayerControlsBytecodePatch.bottomUiContainerResourceId + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottomUiContainerResourceId } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/ControlsLayoutInflateFingerprint.kt similarity index 53% rename from src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/ControlsLayoutInflateFingerprint.kt index 5f75ca730..9b04242a7 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/hideendscreencards/bytecode/fingerprints/LayoutCircleFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/ControlsLayoutInflateFingerprint.kt @@ -1,22 +1,22 @@ -package app.revanced.patches.youtube.layout.hideendscreencards.bytecode.fingerprints +package app.revanced.patches.youtube.misc.playercontrols.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.layout.hideendscreencards.resource.patch.HideEndscreenCardsResourcePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode -object LayoutCircleFingerprint : MethodFingerprint( +object ControlsLayoutInflateFingerprint : MethodFingerprint( opcodes = listOf( - Opcode.CONST, - Opcode.CONST_4, Opcode.INVOKE_VIRTUAL, Opcode.MOVE_RESULT_OBJECT, Opcode.CHECK_CAST, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT ), customFingerprint = { methodDef -> methodDef.implementation?.instructions?.any { instruction -> instruction.opcode.ordinal == Opcode.CONST.ordinal && - (instruction as? WideLiteralInstruction)?.wideLiteral == HideEndscreenCardsResourcePatch.layoutCircle + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.controlsLayoutStubResourceId } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt index 91e0acb01..6c7f87be0 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/PlayerControlsVisibilityFingerprint.kt @@ -1,6 +1,5 @@ package app.revanced.patches.youtube.misc.playercontrols.fingerprints - import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PlayerControlsVisibilityFingerprint : MethodFingerprint( diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/VisibilityNegatedFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/VisibilityNegatedFingerprint.kt new file mode 100644 index 000000000..85e9b0d3c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/VisibilityNegatedFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.misc.playercontrols.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VisibilityNegatedFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), opcodes = listOf( + Opcode.IF_EQZ + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/VisibilityNegatedParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/VisibilityNegatedParentFingerprint.kt new file mode 100644 index 000000000..1929e0390 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/fingerprints/VisibilityNegatedParentFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.misc.playercontrols.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VisibilityNegatedParentFingerprint : MethodFingerprint( + returnType = "V", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.educationTextViewResourceId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/resource/patch/BottomControlsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/resource/patch/BottomControlsResourcePatch.kt deleted file mode 100644 index fbba6efd3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playercontrols/resource/patch/BottomControlsResourcePatch.kt +++ /dev/null @@ -1,85 +0,0 @@ -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.DomFileEditor -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch -import app.revanced.patches.youtube.misc.playercontrols.annotation.PlayerControlsCompatibility - -@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 { - override fun execute(context: ResourceContext): PatchResult { - resourceContext = context - targetXmlEditor = context.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 resourceContext: ResourceContext - 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 = - resourceContext.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() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt deleted file mode 100644 index d74d8bbbb..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/annotation/PlayerOverlaysHookCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.playeroverlay.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PlayerOverlaysHookCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt index 1defdfe65..dab2e0677 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/fingerprint/PlayerOverlaysOnFinishInflateFingerprint.kt @@ -1,10 +1,9 @@ package app.revanced.patches.youtube.misc.playeroverlay.fingerprint - import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> + null, null, null, null, null, { methodDef -> methodDef.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && methodDef.name == "onFinishInflate" } ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/patch/PlayerOverlaysHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/patch/PlayerOverlaysHookPatch.kt index 9b1c95bc4..83cabc5f5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/patch/PlayerOverlaysHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playeroverlay/patch/PlayerOverlaysHookPatch.kt @@ -8,16 +8,14 @@ import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.playeroverlay.annotation.PlayerOverlaysHookCompatibility import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.UTILS_PATH @Name("player-overlays-hook") @Description("Hook for adding custom overlays to the video player.") -@PlayerOverlaysHookCompatibility +@YouTubeCompatibility @Version("0.0.1") -@DependsOn([IntegrationsPatch::class]) class PlayerOverlaysHookPatch : BytecodePatch( listOf( PlayerOverlaysOnFinishInflateFingerprint @@ -28,7 +26,7 @@ class PlayerOverlaysHookPatch : BytecodePatch( val method = PlayerOverlaysOnFinishInflateFingerprint.result!!.mutableMethod method.addInstruction( method.implementation!!.instructions.size - 2, - "invoke-static { p0 }, Lapp/revanced/integrations/patches/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V" + "invoke-static { p0 }, $UTILS_PATH/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V" ) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt deleted file mode 100644 index d9ce962da..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/annotation/PlayerTypeHookCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.playertype.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class PlayerTypeHookCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt index 0eb8e9a11..aa08ea5ab 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/fingerprint/UpdatePlayerTypeFingerprint.kt @@ -6,11 +6,13 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode +//TODO constrain to only match in YoutubePlayerOverlaysLayout? @FuzzyPatternScanMethod(2) object UpdatePlayerTypeFingerprint : MethodFingerprint( "V", AccessFlags.PUBLIC or AccessFlags.FINAL, - opcodes = listOf( + null, + listOf( Opcode.INVOKE_VIRTUAL, Opcode.IGET_OBJECT, Opcode.IF_NE, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt index 75e722072..d23948bd2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/playertype/patch/PlayerTypeHookPatch.kt @@ -8,16 +8,14 @@ import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.playertype.annotation.PlayerTypeHookCompatibility import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.UTILS_PATH @Name("player-type-hook") @Description("Hook to get the current player type of WatchWhileActivity") -@PlayerTypeHookCompatibility +@YouTubeCompatibility @Version("0.0.1") -@DependsOn([IntegrationsPatch::class]) class PlayerTypeHookPatch : BytecodePatch( listOf( UpdatePlayerTypeFingerprint @@ -27,7 +25,7 @@ class PlayerTypeHookPatch : BytecodePatch( // hook YouTubePlayerOverlaysLayout.updatePlayerLayout() UpdatePlayerTypeFingerprint.result!!.mutableMethod.addInstruction( 0, - "invoke-static { p1 }, Lapp/revanced/integrations/patches/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V" + "invoke-static { p1 }, $UTILS_PATH/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V" ) return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/resourceid/patch/SharedResourceIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/resourceid/patch/SharedResourceIdPatch.kt new file mode 100644 index 000000000..c71f44e08 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/resourceid/patch/SharedResourceIdPatch.kt @@ -0,0 +1,58 @@ +package app.revanced.patches.youtube.misc.resourceid.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.mapping.ResourceMappingPatch + +@Name("shared-resource-id") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class SharedResourcdIdPatch : ResourcePatch { + internal companion object { + var abclistmenuitemLabelId: Long = -1 + var accountSwitcherAccessibilityLabelId: Long = -1 + var appearanceStringId: Long = -1 + var bottompaneloverlaytextLabelId: Long = -1 + var bottomUiContainerResourceId: Long = -1 + var controlsLayoutStubResourceId: Long = -1 + var educationTextViewResourceId: Long = -1 + var emptycolorLabelId: Long = -1 + var imageOnlyTabId: Long = -1 + var layoutCircle: Long = -1 + var layoutIcon: Long = -1 + var layoutVideo: Long = -1 + var scrubbingLabelId: Long = -1 + var videoqualityfragmentLabelId: Long = -1 + } + + override fun execute(context: ResourceContext): PatchResult { + + fun findSharedResourceId(type: String, name: String) = ResourceMappingPatch + .resourceMappings + .single { it.type == "$type" && it.name == "$name" }.id + + abclistmenuitemLabelId = findSharedResourceId("layout", "abc_list_menu_item_layout") + accountSwitcherAccessibilityLabelId = findSharedResourceId("string", "account_switcher_accessibility_label") + appearanceStringId = findSharedResourceId("string", "app_theme_appearance_dark") + bottompaneloverlaytextLabelId = findSharedResourceId("id", "bottom_panel_overlay_text") + bottomUiContainerResourceId = findSharedResourceId("id", "bottom_ui_container_stub") + controlsLayoutStubResourceId = findSharedResourceId("id", "controls_layout_stub") + educationTextViewResourceId = findSharedResourceId("id", "user_education_text_view") + emptycolorLabelId = findSharedResourceId("color", "inline_time_bar_colorized_bar_empty_color_dark") + imageOnlyTabId = findSharedResourceId("layout", "image_only_tab") + layoutCircle = findSharedResourceId("layout", "endscreen_element_layout_circle") + layoutIcon = findSharedResourceId("layout", "endscreen_element_layout_icon") + layoutVideo = findSharedResourceId("layout", "endscreen_element_layout_video") + scrubbingLabelId = findSharedResourceId("dimen", "vertical_touch_offset_to_enter_fine_scrubbing") + videoqualityfragmentLabelId = findSharedResourceId("layout", "video_quality_bottom_sheet_list_fragment_title") + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/DislikeFingerprint.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/DislikeFingerprint.kt index 81c56995c..ffdbc9465 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/DislikeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/DislikeFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints +package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/LikeFingerprint.kt similarity index 82% rename from src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/LikeFingerprint.kt index f3d9a8f04..3fdb2d649 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/LikeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/LikeFingerprint.kt @@ -1,11 +1,10 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints +package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags - @FuzzyPatternScanMethod(2) object LikeFingerprint : MethodFingerprint( "V", diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/RemoveLikeFingerprint.kt similarity index 78% rename from src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/RemoveLikeFingerprint.kt index 17b43b252..49b8b5587 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/returnyoutubedislike/fingerprints/RemoveLikeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/RemoveLikeFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.returnyoutubedislike.fingerprints +package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/TextComponentSpecFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/TextComponentSpecFingerprint.kt new file mode 100644 index 000000000..df50e17fb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/fingerprints/TextComponentSpecFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object TextComponentSpecFingerprint : MethodFingerprint( + returnType = "L", + access = AccessFlags.STATIC.getValue(), + opcodes = listOf(Opcode.CMPL_FLOAT), + customFingerprint = { methodDef -> + methodDef.implementation!!.instructions.any { + ((it as? NarrowLiteralInstruction)?.narrowLiteral == 16842907) + } + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/patch/ReturnYouTubeDislikeBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/patch/ReturnYouTubeDislikeBytecodePatch.kt new file mode 100644 index 000000000..e0f151297 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/bytecode/patch/ReturnYouTubeDislikeBytecodePatch.kt @@ -0,0 +1,81 @@ +package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.MethodFingerprintExtensions.name +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints.* +import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.UTILS_PATH + +@Name("return-youtube-dislike-bytecode-patch") +@DependsOn([LegacyVideoIdPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class ReturnYouTubeDislikeBytecodePatch : BytecodePatch( + listOf( + DislikeFingerprint, + LikeFingerprint, + RemoveLikeFingerprint, + TextComponentSpecFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + listOf( + LikeFingerprint.toPatch(Vote.LIKE), + DislikeFingerprint.toPatch(Vote.DISLIKE), + RemoveLikeFingerprint.toPatch(Vote.REMOVE_LIKE) + ).forEach { (fingerprint, vote) -> + with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) { + mutableMethod.addInstructions( + 0, + """ + const/4 v0, ${vote.value} + invoke-static {v0}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->sendVote(I)V + """ + ) + } + } + + LegacyVideoIdPatch.injectCall("$INTEGRATIONS_RYD_CLASS_DESCRIPTOR->newVideoLoaded(Ljava/lang/String;)V") + + val createComponentResult = TextComponentSpecFingerprint.result ?: return PatchResultError("Failed to find TextComponentSpecFingerprint method.") + val createComponentMethod = createComponentResult.mutableMethod + + val conversionContextParam = 5 + val textRefParam = createComponentMethod.parameters.size - 2 + + createComponentMethod.addInstructions( + 0, + """ + move-object/from16 v7, p$conversionContextParam + move-object/from16 v8, p$textRefParam + invoke-static {v7, v8}, $INTEGRATIONS_RYD_CLASS_DESCRIPTOR->onComponentCreated(Ljava/lang/Object;Ljava/util/concurrent/atomic/AtomicReference;)V + """ + ) + + return PatchResultSuccess() + } + private companion object { + const val INTEGRATIONS_RYD_CLASS_DESCRIPTOR = + "$UTILS_PATH/ReturnYouTubeDislikePatch;" + } + + private fun MethodFingerprint.toPatch(voteKind: Vote) = VotePatch(this, voteKind) + + private data class VotePatch(val fingerprint: MethodFingerprint, val voteKind: Vote) + + private enum class Vote(val value: Int) { + LIKE(1), + DISLIKE(-1), + REMOVE_LIKE(0) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/resource/ReturnYouTubeDislikePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/resource/ReturnYouTubeDislikePatch.kt new file mode 100644 index 000000000..df251a46f --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/returnyoutubedislike/resource/ReturnYouTubeDislikePatch.kt @@ -0,0 +1,46 @@ +package app.revanced.patches.youtube.misc.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.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.patch.ReturnYouTubeDislikeBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("return-youtube-dislike") +@Description("Shows the dislike count of videos using the Return YouTube Dislike API.") +@DependsOn( + [ + SettingsPatch::class, + ReturnYouTubeDislikeBytecodePatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ReturnYouTubeDislikePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add ReVanced Settings + */ + ResourceHelper.addReVancedSettings( + context, + "PREFERENCE: RETURN_YOUTUBE_DISLIKE" + ) + + ResourceHelper.patchSuccess( + context, + "return-youtube-dislike" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/annotations/SettingsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/annotations/SettingsCompatibility.kt deleted file mode 100644 index 5fa1408ad..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/annotations/SettingsCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class SettingsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt deleted file mode 100644 index 11395105f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/LicenseActivityFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object LicenseActivityFingerprint : MethodFingerprint( - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("LicenseActivity;") && methodDef.name == "onCreate" - } -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeConstructorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeConstructorFingerprint.kt deleted file mode 100644 index 599314a4f..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeConstructorFingerprint.kt +++ /dev/null @@ -1,12 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags - -object ThemeConstructorFingerprint : MethodFingerprint( - "L", - AccessFlags.PUBLIC or AccessFlags.STATIC, - listOf("L"), - strings = listOf("settings.SettingsActivity", ":android:show_fragment", "settings.GeneralPrefsFragment") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt deleted file mode 100644 index 9fc0065e7..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterAppFingerprint.kt +++ /dev/null @@ -1,22 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.Opcode - -object ThemeSetterAppFingerprint : MethodFingerprint( - "L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( - Opcode.CONST, //target reference - Opcode.GOTO, - Opcode.CONST, //target reference - Opcode.INVOKE_DIRECT, - Opcode.RETURN_OBJECT, - Opcode.NEW_INSTANCE, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.SGET_OBJECT, - Opcode.IF_NE, - Opcode.CONST, //target reference - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt index d57892735..6cd9c89f4 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/fingerprints/ThemeSetterSystemFingerprint.kt @@ -1,16 +1,17 @@ package app.revanced.patches.youtube.misc.settings.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch -import org.jf.dexlib2.Opcode +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode object ThemeSetterSystemFingerprint : MethodFingerprint( "L", opcodes = listOf(Opcode.RETURN_OBJECT), customFingerprint = { methodDef -> - methodDef.implementation?.instructions?.any { - it.opcode.ordinal == Opcode.CONST.ordinal && (it as WideLiteralInstruction).wideLiteral == SettingsResourcePatch.appearanceStringId + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.appearanceStringId } == true } ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsBytecodePatch.kt new file mode 100644 index 000000000..20755a11d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsBytecodePatch.kt @@ -0,0 +1,112 @@ +package app.revanced.patches.youtube.misc.settings.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.extensions.injectTheme +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("settings-bytecode-patch") +@DependsOn( + [ + IntegrationsPatch::class, + ResourceMappingPatch::class, + SharedResourcdIdPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SettingsBytecodePatch : BytecodePatch( + listOf(ThemeSetterSystemFingerprint) +) { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "Theme.YouTube.Light", + "Theme.YouTube.Light.DarkerPalette" + ).map { name -> + ResourceMappingPatch.resourceMappings.single { it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // primary theme + val insertIndex = index - 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.IF_NE) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (instructions.elementAt(index) as Instruction31i).registerA + mutableMethod.implementation!!.injectTheme(mutableMethod.implementation!!.instructions.size - 1 , viewRegister, "setPrimaryTheme") + } + + resourceIds[1] -> { // secondary theme + val insertIndex = index - 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.IF_NE) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (instructions.elementAt(index) as Instruction31i).registerA + mutableMethod.implementation!!.injectTheme(index + 2, viewRegister, "setSecondaryTheme") + } +/* + resourceIds[2] -> { // tertiary theme + val insertIndex = index - 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.IF_NE) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + val viewRegister = (instructions.elementAt(index) as Instruction31i).registerA + mutableMethod.implementation!!.injectTheme(index + 2, viewRegister, "setTertiaryTheme") + } +*/ + } + } + else -> return@forEachIndexed + } + } + } + } + } + + // apply the current theme of the settings page + with(ThemeSetterSystemFingerprint.result!!) { + with(mutableMethod) { + val call = "invoke-static {v0}, $INTEGRATIONS_PATH/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V" + + addInstruction( + scanResult.patternScanResult!!.startIndex, + call + ) + + addInstruction( + mutableMethod.implementation!!.instructions.size - 1, + call + ) + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt deleted file mode 100644 index 2c1ee88ba..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsPatch.kt +++ /dev/null @@ -1,160 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.bytecode.patch - -import app.revanced.extensions.toErrorResult -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.util.AbstractPreferenceScreen -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.LicenseActivityFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeConstructorFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterAppFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint -import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsResourcePatch -import org.jf.dexlib2.util.MethodUtil - -@Patch -@DependsOn( - [ - IntegrationsPatch::class, - SettingsResourcePatch::class, - ] -) -@Name("settings") -@Description("Adds settings for ReVanced to YouTube.") -@SettingsCompatibility -@Version("0.0.1") -class SettingsPatch : BytecodePatch( - listOf(LicenseActivityFingerprint, ThemeSetterSystemFingerprint, ThemeConstructorFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - fun buildInvokeInstructionsString( - registers: String = "v0", - classDescriptor: String = THEME_HELPER_DESCRIPTOR, - methodName: String = SET_THEME_METHOD_NAME, - parameters: String = "Ljava/lang/Object;" - ) = "invoke-static {$registers}, $classDescriptor->$methodName($parameters)V" - - // apply the current theme of the settings page - ThemeSetterSystemFingerprint.result!!.let { result -> - val call = buildInvokeInstructionsString() - result.mutableMethod.apply { - addInstruction( - result.scanResult.patternScanResult!!.startIndex, call - ) - addInstructions( - implementation!!.instructions.size - 1, call - ) - } - } - - // set the theme based on the preference of the app - with((ThemeConstructorFingerprint.result?.let { - ThemeSetterAppFingerprint.apply { - if (!resolve(context, it.classDef)) return ThemeSetterAppFingerprint.toErrorResult() - } - } ?: return ThemeConstructorFingerprint.toErrorResult()).result!!) { - fun buildInstructionsString(theme: Int) = """ - const/4 v0, 0x$theme - ${buildInvokeInstructionsString(parameters = "I")} - """ - - val patternScanResult = scanResult.patternScanResult!! - - mutableMethod.apply { - addInstructions( - patternScanResult.endIndex + 1, buildInstructionsString(1) - ) - addInstructions( - patternScanResult.endIndex - 7, buildInstructionsString(0) - ) - - addInstructions( - patternScanResult.endIndex - 9, buildInstructionsString(1) - ) - addInstructions( - implementation!!.instructions.size - 2, buildInstructionsString(0) - ) - } - - } - - // set the theme based on the preference of the device - with(LicenseActivityFingerprint.result!!) licenseActivity@{ - with(mutableMethod) { - fun buildSettingsActivityInvokeString( - registers: String = "p0", - classDescriptor: String = SETTINGS_ACTIVITY_DESCRIPTOR, - methodName: String = "initializeSettings", - parameters: String = this@licenseActivity.mutableClass.type - ) = buildInvokeInstructionsString(registers, classDescriptor, methodName, parameters) - - // initialize the settings - addInstructions( - 1, """ - ${buildSettingsActivityInvokeString()} - return-void - """ - ) - - // set the current theme - addInstruction(0, buildSettingsActivityInvokeString(methodName = "setTheme")) - } - - // remove method overrides - with(mutableClass) { - methods.removeIf { it.name != "onCreate" && !MethodUtil.isConstructor(it) } - } - } - - return PatchResultSuccess() - } - - internal companion object { - private const val INTEGRATIONS_PACKAGE = "app/revanced/integrations" - - private const val SETTINGS_ACTIVITY_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/settingsmenu/ReVancedSettingActivity;" - - private const val THEME_HELPER_DESCRIPTOR = "L$INTEGRATIONS_PACKAGE/utils/ThemeHelper;" - private const val SET_THEME_METHOD_NAME = "setTheme" - - fun addString(identifier: String, value: String, formatted: Boolean = true) = - SettingsResourcePatch.addString(identifier, value, formatted) - - fun addPreferenceScreen(preferenceScreen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) = - SettingsResourcePatch.addPreferenceScreen(preferenceScreen) - - fun addPreference(preference: Preference) = SettingsResourcePatch.addPreference(preference) - - fun renameIntentsTargetPackage(newPackage: String) { - SettingsResourcePatch.overrideIntentsTargetPackage = newPackage - } - } - - /** - * Preference screens patches should add their settings to. - */ - internal object PreferenceScreen : AbstractPreferenceScreen() { - val ADS = Screen("ads", "Ads", "Ad related settings") - val INTERACTIONS = Screen("interactions", "Interaction", "Settings related to interactions") - val LAYOUT = Screen("layout", "Layout", "Settings related to the layout") - val MISC = Screen("misc", "Misc", "Miscellaneous patches") - - override fun commit(screen: app.revanced.patches.shared.settings.preference.impl.PreferenceScreen) { - addPreferenceScreen(screen) - } - } - - override fun close() = PreferenceScreen.close() -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsSecondaryBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsSecondaryBytecodePatch.kt new file mode 100644 index 000000000..67754ec09 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/bytecode/patch/SettingsSecondaryBytecodePatch.kt @@ -0,0 +1,47 @@ +package app.revanced.patches.youtube.misc.settings.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("settings-secondary-bytecode-patch") +@DependsOn([SharedResourcdIdPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class SettingsSecondaryBytecodePatch : BytecodePatch( + listOf(ThemeSetterSystemFingerprint) +) { + override fun execute(context: BytecodeContext): PatchResult { + val ThemeHelper = "$INTEGRATIONS_PATH/utils/ThemeHelper;" + + // apply the current theme of the settings page + with(ThemeSetterSystemFingerprint.result!!) { + with(mutableMethod) { + val call = "invoke-static {v0}, $ThemeHelper->setTheme(Ljava/lang/Object;)V" + + addInstruction( + scanResult.patternScanResult!!.startIndex, + call + ) + + addInstruction( + mutableMethod.implementation!!.instructions.size - 1, + call + ) + } + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsPatch.kt new file mode 100644 index 000000000..db00ceb7d --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsPatch.kt @@ -0,0 +1,100 @@ +package app.revanced.patches.youtube.misc.settings.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patches.youtube.misc.manifest.patch.FixLocaleConfigErrorPatch +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsBytecodePatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.settings.AbstractSettingsResourcePatch +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources +import org.w3c.dom.Element + +@Patch +@Name("settings") +@Description("Applies mandatory patches to implement ReVanced settings into the application.") +@DependsOn( + [ + FixLocaleConfigErrorPatch::class, + IntegrationsPatch::class, + SharedResourcdIdPatch::class, + SettingsBytecodePatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SettingsPatch : AbstractSettingsResourcePatch( + "youtube/settings", + "youtube/settings/host", + true +) { + override fun execute(context: ResourceContext): PatchResult { + super.execute(context) + + /* + * create directory for the untranslated language resources + */ + context["res/values-v21"].mkdirs() + + arrayOf( + ResourceUtils.ResourceGroup( + "layout", + "revanced_settings_toolbar.xml", + "revanced_settings_with_toolbar.xml", + "revanced_settings_with_toolbar_layout.xml" + ), + ResourceUtils.ResourceGroup( + "values-v21", + "strings.xml" + ) + ).forEach { resourceGroup -> + context.copyResources("youtube/settings", resourceGroup) + } + + /* + * remove revanced settings divider + */ + arrayOf("Theme.YouTube.Settings", "Theme.YouTube.Settings.Dark").forEach { themeName -> + context.xmlEditor["res/values/styles.xml"].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + val newElement: Element = createElement("item") + newElement.setAttribute("name", "android:listDivider") + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + if (node.getAttribute("name") == themeName) { + newElement.appendChild(createTextNode("@null")) + + node.appendChild(newElement) + } + } + } + } + } + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: EXTENDED_SETTINGS", + "SETTINGS: ABOUT" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt deleted file mode 100644 index 2bd580d34..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/settings/resource/patch/SettingsResourcePatch.kt +++ /dev/null @@ -1,169 +0,0 @@ -package app.revanced.patches.youtube.misc.settings.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.DomFileEditor -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patches.shared.mapping.misc.patch.ResourceMappingPatch -import app.revanced.patches.shared.settings.preference.addPreference -import app.revanced.patches.shared.settings.preference.impl.ArrayResource -import app.revanced.patches.shared.settings.preference.impl.Preference -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.resource.patch.AbstractSettingsResourcePatch -import app.revanced.patches.youtube.misc.settings.annotations.SettingsCompatibility -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.util.resources.ResourceUtils -import app.revanced.util.resources.ResourceUtils.copyResources -import org.w3c.dom.Node - -@Name("settings-resource-patch") -@DependsOn([ResourceMappingPatch::class]) -@SettingsCompatibility -@Description("Applies mandatory patches to implement ReVanced settings into the application.") -@Version("0.0.1") -class SettingsResourcePatch : AbstractSettingsResourcePatch( - "revanced_prefs", - "settings" -) { - override fun execute(context: ResourceContext): PatchResult { - super.execute(context) - - /* - * used by a fingerprint of SettingsPatch - */ - appearanceStringId = ResourceMappingPatch.resourceMappings.find { - it.type == "string" && it.name == "app_theme_appearance_dark" - }!!.id - - /* - * create missing directory for the resources - */ - context["res/drawable-ldrtl-xxxhdpi"].mkdirs() - - /* - * copy layout resources - */ - arrayOf( - ResourceUtils.ResourceGroup( - "layout", - "revanced_settings_toolbar.xml", - "revanced_settings_with_toolbar.xml", - "revanced_settings_with_toolbar_layout.xml" - ), ResourceUtils.ResourceGroup( - // required resource for back button, because when the base APK is used, this resource will not exist - "drawable-xxxhdpi", "quantum_ic_arrow_back_white_24.png" - ), ResourceUtils.ResourceGroup( - // required resource for back button, because when the base APK is used, this resource will not exist - "drawable-ldrtl-xxxhdpi", "quantum_ic_arrow_back_white_24.png" - ) - ).forEach { resourceGroup -> - context.copyResources("settings", resourceGroup) - } - - preferencesEditor = context.xmlEditor["res/xml/settings_fragment.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 { - // Used by a fingerprint of SettingsPatch - // this field is located in the SettingsResourcePatch - // because if it were to be defined in the SettingsPatch companion object, - // the companion object could be initialized before ResourceMappingResourcePatch has executed. - internal var appearanceStringId: Long = -1 - - // if this is not null, all intents will be renamed to this - var overrideIntentsTargetPackage: String? = null - - private var preferencesNode: Node? = null - - private var preferencesEditor: DomFileEditor? = null - set(value) { - field = value - preferencesNode = value.getNode("PreferenceScreen") - } - - /* Companion delegates */ - - /** - * Add a preference fragment to the main preferences. - * - * @param preference The preference to add. - */ - fun addPreference(preference: Preference) = - preferencesNode!!.addPreference(preference) { it.include() } - - /** - * 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) = - AbstractSettingsResourcePatch.addString(identifier, value, formatted) - - /** - * Add an array to the resources. - * - * @param arrayResource The array resource to add. - */ - fun addArray(arrayResource: ArrayResource) = AbstractSettingsResourcePatch.addArray(arrayResource) - - /** - * Add a preference to the settings. - * - * @param preferenceScreen The name of the preference screen. - */ - fun addPreferenceScreen(preferenceScreen: PreferenceScreen) = addPreference(preferenceScreen) - } - - override fun close() { - super.close() - - // 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 - }) - } - } - - preferencesEditor?.close() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt index 2c6d4720c..6b77cad89 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/AppendTimeFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints +package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt similarity index 84% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt index d17333720..7b38f4b89 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/NextGenWatchLayoutFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints - +package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.util.MethodUtil diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt index 975bdfe7a..c9ab025be 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/PlayerOverlaysLayoutInitFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints - +package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt similarity index 91% rename from src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt index 822484a89..b859cff73 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/fingerprints/RectangleFieldInvalidatorFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.layout.sponsorblock.bytecode.fingerprints - +package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.iface.instruction.ReferenceInstruction diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt new file mode 100644 index 000000000..13e53c381 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/patch/SponsorBlockBytecodePatch.kt @@ -0,0 +1,164 @@ +package app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.misc.playercontrols.bytecode.patch.PlayerControlsBytecodePatch +import app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints.* +import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.timebar.HookTimebarPatch +import app.revanced.shared.util.bytecode.BytecodeHelper +import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction +import org.jf.dexlib2.iface.instruction.formats.Instruction22c +import org.jf.dexlib2.iface.instruction.formats.Instruction35c +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.Opcode + +@Name("sponsorblock-bytecode-patch") +@DependsOn( + [ + MainstreamVideoIdPatch::class, + PlayerControlsBytecodePatch::class, + SharedResourcdIdPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SponsorBlockBytecodePatch : BytecodePatch( + listOf( + NextGenWatchLayoutFingerprint, + AppendTimeFingerprint, + PlayerOverlaysLayoutInitFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + + /* + inject MainstreamVideoIdPatch + */ + MainstreamVideoIdPatch.injectCall("$INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setCurrentVideoId(Ljava/lang/String;)V") + + /* + Seekbar drawing + */ + insertResult = HookTimebarPatch.SetTimbarFingerprintResult + insertMethod = insertResult.mutableMethod + val insertInstructions = insertMethod.implementation!!.instructions + + /* + Get the instance of the seekbar rectangle + */ + for ((index, instruction) in insertInstructions.withIndex()) { + if (instruction.opcode != Opcode.IGET_OBJECT) continue + val seekbarRegister = (instruction as Instruction22c).registerB + insertMethod.addInstruction( + index - 1, + "invoke-static {v$seekbarRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarRect(Ljava/lang/Object;)V" + ) + break + } + + for ((index, instruction) in insertInstructions.withIndex()) { + if (instruction.opcode != Opcode.INVOKE_STATIC) continue + + val invokeInstruction = instruction as Instruction35c + if ((invokeInstruction.reference as MethodReference).name != "round") continue + + val insertIndex = index + 2 + + // set the thickness of the segment + insertMethod.addInstruction( + insertIndex, + "invoke-static {v${invokeInstruction.registerC}}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->setSponsorBarThickness(I)V" + ) + break + } + + /* + Set rectangle absolute left and right positions + */ + val drawRectangleInstructions = insertInstructions.filter { + it is ReferenceInstruction && (it.reference as? MethodReference)?.name == "drawRect" && it is FiveRegisterInstruction + }.map { // TODO: improve code + insertInstructions.indexOf(it) to (it as FiveRegisterInstruction).registerD + } + + mapOf( + "setSponsorBarAbsoluteLeft" to 3, + "setSponsorBarAbsoluteRight" to 0 + ).forEach { (string, int) -> + val (index, register) = drawRectangleInstructions[int] + injectCallRectangle(index, register, string) + } + + /* + Draw segment + */ + val drawSegmentInstructionInsertIndex = (insertInstructions.size - 1 - 2) + val (canvasInstance, centerY) = (insertInstructions[drawSegmentInstructionInsertIndex] as FiveRegisterInstruction).let { + it.registerC to it.registerE + } + insertMethod.addInstruction( + drawSegmentInstructionInsertIndex, + "invoke-static {v$canvasInstance, v$centerY}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->drawSponsorTimeBars(Landroid/graphics/Canvas;F)V" + ) + + /* + Voting & Shield button + */ + + arrayOf("ShieldButton", "VotingButton").forEach { button -> + PlayerControlsBytecodePatch.initializeSB("$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/$button;") + PlayerControlsBytecodePatch.injectVisibility("$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/$button;") + PlayerControlsBytecodePatch.injectVisibilityNegated("$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/$button;") + } + + // set SegmentHelperLayout.context to the player layout instance + val instanceRegister = 0 + NextGenWatchLayoutFingerprint.result!!.mutableMethod.addInstruction( + 3, // after super call + "invoke-static/range {p$instanceRegister}, Lapp/revanced/integrations/sponsorblock/PlayerController;->addSkipSponsorView15(Landroid/view/View;)V" + ) + + BytecodeHelper.injectInit(context, "FirstRun", "initializationSB") + BytecodeHelper.patchStatus(context, "Sponsorblock") + + return PatchResultSuccess() + } + + internal companion object { + const val INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR = + "Lapp/revanced/integrations/sponsorblock" + + const val INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR = + "$INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/PlayerController;" + + lateinit var insertResult: MethodFingerprintResult + lateinit var insertMethod: MutableMethod + + /** + * Adds an invoke-static instruction, called with the new id when the video changes + * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` + */ + fun injectCallRectangle( + insertIndex: Int, + targetRegister: Int, + methodDescriptor: String + ) { + insertMethod.addInstruction( + insertIndex, + "invoke-static {v$targetRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->$methodDescriptor(Landroid/graphics/Rect;)V" + ) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/patch/SponsorBlockSecondaryBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/patch/SponsorBlockSecondaryBytecodePatch.kt new file mode 100644 index 000000000..6dffa9b32 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/bytecode/patch/SponsorBlockSecondaryBytecodePatch.kt @@ -0,0 +1,80 @@ +package app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.shared.extensions.findMutableMethodOf +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.mapping.ResourceMappingPatch +import org.jf.dexlib2.iface.instruction.formats.Instruction31i +import org.jf.dexlib2.Opcode + +@Name("sponsorblock-secondary-bytecode-patch") +@DependsOn([ResourceMappingPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class SponsorBlockSecondaryBytecodePatch : BytecodePatch() { + + // list of resource names to get the id of + private val resourceIds = arrayOf( + "string" to "total_time", + "layout" to "player_overlays" + ).map { (type, name) -> + ResourceMappingPatch + .resourceMappings + .single { it.type == type && it.name == name }.id + } + + override fun execute(context: BytecodeContext): PatchResult { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + with(method.implementation) { + this?.instructions?.forEachIndexed { index, instruction -> + when (instruction.opcode) { + Opcode.CONST -> { + when ((instruction as Instruction31i).wideLiteral) { + resourceIds[0] -> { // total time + val insertIndex = index + 3 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.IGET_OBJECT) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + mutableMethod.addInstructions( + insertIndex, """ + invoke-static {p1}, Lapp/revanced/integrations/sponsorblock/SponsorBlockUtils;->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String; + move-result-object p1 + """ + ) + + } + + resourceIds[1] -> { // player overlay + val insertIndex = index + 4 + val invokeInstruction = instructions.elementAt(insertIndex) + if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed + + val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) + + mutableMethod.addInstruction( + insertIndex, + "invoke-static {p0}, Lapp/revanced/integrations/sponsorblock/player/ui/SponsorBlockView;->initialize(Ljava/lang/Object;)V" + ) + } + } + } + else -> return@forEachIndexed + } + } + } + } + } + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt new file mode 100644 index 000000000..6ea30740c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/sponsorblock/resource/patch/SponsorBlockResourcePatch.kt @@ -0,0 +1,113 @@ +package app.revanced.patches.youtube.misc.sponsorblock.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch.SponsorBlockBytecodePatch +import app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch.SponsorBlockSecondaryBytecodePatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode + +@Patch +@Name("sponsorblock") +@Description("Integrate SponsorBlock.") +@DependsOn( + [ + SettingsPatch::class, + SponsorBlockBytecodePatch::class, + SponsorBlockSecondaryBytecodePatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SponsorBlockResourcePatch : ResourcePatch { + + override fun execute(context: ResourceContext): PatchResult { + /* + merge SponsorBlock drawables to main drawables + */ + + 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" + ) + ).forEach { resourceGroup -> + context.copyResources("youtube/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 = this.javaClass.classLoader.getResourceAsStream("youtube/sponsorblock/host/$path/$resource.xml")!! + + val targetXmlEditor = context.xmlEditor["res/$path/$resource.xml"] + "RelativeLayout".copyXmlNode( + context.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 attribute for a specific node only + if (!(view.hasAttributes() && view.attributes.getNamedItem("android:id").nodeValue.endsWith("player_video_heading"))) continue + + // voting button id from the voting button view from the youtube_controls_layout.xml host file + val SBButtonId = "@+id/sponsorblock_button" + + view.attributes.getNamedItem("android:layout_toStartOf").nodeValue = SBButtonId + + break + } + }.close() // close afterwards + } + } + + /* + add ReVanced Settings + */ + ResourceHelper.addReVancedSettings( + context, + "PREFERENCE: SPONSOR_BLOCK" + ) + + ResourceHelper.patchSuccess( + context, + "sponsorblock" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/swiperefresh/fingerprint/SwipeRefreshLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/swiperefresh/fingerprint/SwipeRefreshLayoutFingerprint.kt new file mode 100644 index 000000000..42bb4151b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/swiperefresh/fingerprint/SwipeRefreshLayoutFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.misc.swiperefresh.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object SwipeRefreshLayoutFingerprint : MethodFingerprint( + returnType = "Z", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf(), + opcodes = listOf( + Opcode.RETURN, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT, + Opcode.RETURN + ), + customFingerprint = { methodDef -> + methodDef.definingClass == "Landroidx/swiperefreshlayout/widget/SwipeRefreshLayout;" + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/swiperefresh/patch/SwipeRefreshPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/swiperefresh/patch/SwipeRefreshPatch.kt new file mode 100644 index 000000000..4a5065ca2 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/swiperefresh/patch/SwipeRefreshPatch.kt @@ -0,0 +1,35 @@ +package app.revanced.patches.youtube.misc.swiperefresh.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.swiperefresh.fingerprint.SwipeRefreshLayoutFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("enable-swipe-refresh") +@Description("Enable swipe refresh.") +@YouTubeCompatibility +@Version("0.0.1") +class SwipeRefreshPatch : BytecodePatch( + listOf( + SwipeRefreshLayoutFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val result = SwipeRefreshLayoutFingerprint.result!! + val method = result.mutableMethod + val index = result.scanResult.patternScanResult!!.endIndex + val register = (method.instruction(index) as OneRegisterInstruction).registerA + + method.addInstruction(index, "const/4 v$register, 0x0") + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/theme/patch/ThemePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/theme/patch/ThemePatch.kt new file mode 100644 index 000000000..216f46b9c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/theme/patch/ThemePatch.kt @@ -0,0 +1,74 @@ +package app.revanced.patches.youtube.misc.theme.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.patches.theme.bytecode.GeneralThemePatch +import app.revanced.shared.util.resources.ResourceHelper +import org.w3c.dom.Element + +@Patch +@Name("theme") +@Description("Applies a custom theme (default: amoled).") +@DependsOn( + [ + GeneralThemePatch::class, + PatchOptions::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class ThemePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + arrayOf("values", "values-v31").forEach { valuesPath -> + setTheme(context, valuesPath) + } + + ResourceHelper.themePatchSuccess( + context, + "default", + "amoled" + ) + + ResourceHelper.themePatchSuccess( + context, + "materialyou", + "mix" + ) + + return PatchResultSuccess() + } + companion object { + + fun setTheme( + context: ResourceContext, + valuesPath: String + ) { + context.xmlEditor["res/$valuesPath/colors.xml"].use { editor -> + val resourcesNode = editor.file.getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + node.textContent = when (node.getAttribute("name")) { + "yt_black0", "yt_black1", "yt_black1_opacity95", "yt_black1_opacity98", "yt_black2", "yt_black3", + "yt_black4", "yt_status_bar_background_dark", "material_grey_850" -> PatchOptions.darkThemeBackgroundColor + + else -> continue + } + } + } + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/translations/patch/TranslationsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/translations/patch/TranslationsPatch.kt new file mode 100644 index 000000000..390be3117 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/translations/patch/TranslationsPatch.kt @@ -0,0 +1,70 @@ +package app.revanced.patches.youtube.misc.translations.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch +@Name("translations") +@Description("Add Crowdin Translations") +@DependsOn([SettingsPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class TranslationsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + LANGUAGE_LIST.forEach { language -> + val directory = "values-" + "$language" + "-v21" + val relativePath = "$language/strings.xml" + + context["res/$directory"].mkdir() + + Files.copy( + this.javaClass.classLoader.getResourceAsStream("youtube/translations/$relativePath")!!, + context["res"].resolve("$directory/strings.xml").toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + + ResourceHelper.patchSuccess( + context, + "translations" + ) + + return PatchResultSuccess() + } + + private companion object { + val LANGUAGE_LIST = arrayOf( + "ar", + "az-rAZ", + "be-rBY", + "de-rDE", + "es-rES", + "fr-rFR", + "id-rID", + "in", + "ja-rJP", + "ko-rKR", + "pl-rPL", + "pt-rBR", + "ru-rRU", + "sk-rSK", + "tr-rTR", + "uk-rUA", + "vi-rVN", + "zh-rCN" + ) + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt deleted file mode 100644 index e64280077..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/annotation/VideoInformationCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.video.information.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class VideoInformationCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt deleted file mode 100644 index 13f82a926..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/CreateVideoPlayerSeekbarFingerprint.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object CreateVideoPlayerSeekbarFingerprint : MethodFingerprint( - "V", - strings = listOf("timed_markers_width") -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoLengthFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoLengthFingerprint.kt deleted file mode 100644 index 2d9e98682..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoLengthFingerprint.kt +++ /dev/null @@ -1,23 +0,0 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints - - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -import org.jf.dexlib2.Opcode - -object VideoLengthFingerprint : MethodFingerprint( - opcodes = listOf( - Opcode.MOVE_RESULT_WIDE, - Opcode.CMP_LONG, - Opcode.IF_LEZ, - Opcode.IGET_OBJECT, - Opcode.CHECK_CAST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_WIDE, - Opcode.GOTO, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_WIDE, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt deleted file mode 100644 index 4df446b15..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/patch/VideoInformationPatch.kt +++ /dev/null @@ -1,178 +0,0 @@ -package app.revanced.patches.youtube.misc.video.information.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.data.toMethodWalker -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.extensions.or -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.information.annotation.VideoInformationCompatibility -import app.revanced.patches.youtube.misc.video.information.fingerprints.* -import org.jf.dexlib2.AccessFlags -import org.jf.dexlib2.builder.MutableMethodImplementation -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction -import org.jf.dexlib2.immutable.ImmutableMethod -import org.jf.dexlib2.immutable.ImmutableMethodParameter -import org.jf.dexlib2.util.MethodUtil - -@Name("video-information") -@Description("Hooks YouTube to get information about the current playing video.") -@VideoInformationCompatibility -@Version("0.0.1") -@DependsOn([IntegrationsPatch::class]) -class VideoInformationPatch : BytecodePatch( - listOf( - PlayerInitFingerprint, - CreateVideoPlayerSeekbarFingerprint, - PlayerControllerSetTimeReferenceFingerprint, - VideoTimeFingerprint, - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - with(PlayerInitFingerprint.result!!) { - playerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) } - - // hook the player controller for use through integrations - onCreateHook(INTEGRATIONS_CLASS_DESCRIPTOR, "playerController_onCreateHook") - - // seek method - val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method - - // create helper method - val seekHelperMethod = ImmutableMethod( - seekFingerprintResultMethod.definingClass, - "seekTo", - listOf(ImmutableMethodParameter("J", null, "time")), - "Z", - AccessFlags.PUBLIC or AccessFlags.FINAL, - null, null, - MutableMethodImplementation(4) - ).toMutable() - - // get enum type for the seek helper method - val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString() - - // insert helper method instructions - seekHelperMethod.addInstructions( - 0, - """ - sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType - invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z - move-result p1 - return p1 - """ - ) - - // add the seekTo method to the class for the integrations to call - mutableClass.methods.add(seekHelperMethod) - } - - with(CreateVideoPlayerSeekbarFingerprint.result!!) { - val videoLengthMethodResult = VideoLengthFingerprint.also { it.resolve(context, classDef) }.result!! - - with(videoLengthMethodResult.mutableMethod) { - val videoLengthRegisterIndex = videoLengthMethodResult.scanResult.patternScanResult!!.endIndex - 2 - val videoLengthRegister = (instruction(videoLengthRegisterIndex) as OneRegisterInstruction).registerA - val dummyRegisterForLong = videoLengthRegister + 1 // required for long values since they are wide - - addInstruction( - videoLengthMethodResult.scanResult.patternScanResult!!.endIndex, - "invoke-static {v$videoLengthRegister, v$dummyRegisterForLong}, $INTEGRATIONS_CLASS_DESCRIPTOR->setVideoLength(J)V" - ) - } - } - - /* - Set the video time method - */ - with(PlayerControllerSetTimeReferenceFingerprint.result!!) { - timeMethod = context.toMethodWalker(method) - .nextMethod(scanResult.patternScanResult!!.startIndex, true) - .getMethod() as MutableMethod - } - - /* - Set the high precision video time method - */ - highPrecisionTimeMethod = - (object : MethodFingerprint("V", null, listOf("J", "J", "J", "J", "I", "L"), null) {}).also { - it.resolve(context, VideoTimeFingerprint.result!!.classDef) - }.result!!.mutableMethod - - /* - Hook the methods which set the time - */ - highPrecisionTimeHook(INTEGRATIONS_CLASS_DESCRIPTOR, "setVideoTime") - - return PatchResultSuccess() - } - - companion object { - private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/patches/VideoInformation;" - - private lateinit var playerInitMethod: MutableMethod - private lateinit var timeMethod: MutableMethod - private lateinit var highPrecisionTimeMethod: MutableMethod - - private fun MutableMethod.insert(insert: InsertIndex, register: String, descriptor: String) = - addInstruction(insert.index, "invoke-static { $register }, $descriptor") - - private fun MutableMethod.insertTimeHook(insert: InsertIndex, descriptor: String) = - insert(insert, "p1, p2", descriptor) - - /** - * Hook the player controller. - * - * @param targetMethodClass The descriptor for the class to invoke when the player controller is created. - * @param targetMethodName The name of the static method to invoke when the player controller is created. - */ - internal fun onCreateHook(targetMethodClass: String, targetMethodName: String) = - playerInitMethod.insert( - InsertIndex.CREATE, - "v0", - "$targetMethodClass->$targetMethodName(Ljava/lang/Object;)V" - ) - - /** - * Hook the video time. - * - * @param targetMethodClass The descriptor for the static method to invoke when the player controller is created. - * @param targetMethodName The name of the static method to invoke when the player controller is created. - */ - internal fun videoTimeHook(targetMethodClass: String, targetMethodName: String) = - timeMethod.insertTimeHook( - InsertIndex.TIME, - "$targetMethodClass->$targetMethodName(J)V" - ) - - /** - * Hook the high precision video time. - * - * @param targetMethodClass The descriptor for the static method to invoke when the player controller is created. - * @param targetMethodName The name of the static method to invoke when the player controller is created. - */ - internal fun highPrecisionTimeHook(targetMethodClass: String, targetMethodName: String) = - highPrecisionTimeMethod.insertTimeHook( - InsertIndex.HIGH_PRECISION_TIME, - "$targetMethodClass->$targetMethodName(J)V" - ) - - enum class InsertIndex(internal val index: Int) { - CREATE(4), - TIME(2), - HIGH_PRECISION_TIME(0), - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt deleted file mode 100644 index 147801ebe..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/annotations/RememberVideoQualityCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.video.quality.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class RememberVideoQualityCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt deleted file mode 100644 index 08dd6723b..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/patch/RememberVideoQualityPatch.kt +++ /dev/null @@ -1,88 +0,0 @@ -package app.revanced.patches.youtube.misc.video.quality.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstruction -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.quality.annotations.RememberVideoQualityCompatibility -import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualityReferenceFingerprint -import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoQualitySetterFingerprint -import app.revanced.patches.youtube.misc.video.quality.fingerprints.VideoUserQualityChangeFingerprint -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.misc.video.videoid.patch.VideoIdPatch -import org.jf.dexlib2.iface.instruction.ReferenceInstruction -import org.jf.dexlib2.iface.reference.FieldReference - -@Patch -@DependsOn([IntegrationsPatch::class, VideoIdPatch::class, SettingsPatch::class]) -@Name("remember-video-quality") -@Description("Adds the ability to remember the video quality you chose in the video quality flyout.") -@RememberVideoQualityCompatibility -@Version("0.0.1") -class RememberVideoQualityPatch : BytecodePatch( - listOf( - VideoQualitySetterFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_remember_video_quality_last_selected", - StringResource("revanced_remember_video_quality_last_selected_title", "Remember video quality changes"), - true, - StringResource( - "revanced_remember_video_quality_last_selected_summary_on", - "Quality changes apply to all videos" - ), - StringResource( - "revanced_remember_video_quality_last_selected_summary_off", - "Quality changes only apply to the current video and are reverted back to the last remembered quality for future playbacks" - ) - ) - ) - - val setterMethod = VideoQualitySetterFingerprint.result!! - - VideoUserQualityChangeFingerprint.resolve(context, setterMethod.classDef) - val userQualityMethod = VideoUserQualityChangeFingerprint.result!! - - VideoQualityReferenceFingerprint.resolve(context, setterMethod.classDef) - val qualityFieldReference = - VideoQualityReferenceFingerprint.result!!.method.let { method -> - (method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference - } - - VideoIdPatch.injectCall("Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;->newVideoStarted(Ljava/lang/String;)V") - - val qIndexMethodName = - context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name - - setterMethod.mutableMethod.addInstructions( - 0, - """ - iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type} - const-string v1, "$qIndexMethodName" - invoke-static {p1, p2, v0, v1}, Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I - move-result p2 - """, - ) - - userQualityMethod.mutableMethod.addInstruction( - 0, - "invoke-static {p3}, Lapp/revanced/integrations/patches/playback/quality/RememberVideoQualityPatch;->userChangedQuality(I)V" - ) - - return PatchResultSuccess() - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt deleted file mode 100644 index bcecd7d49..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/annotations/CustomPlaybackSpeedCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CustomPlaybackSpeedCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt deleted file mode 100644 index 541601fd1..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/VideoSpeedPatchFingerprint.kt +++ /dev/null @@ -1,11 +0,0 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints - -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import org.jf.dexlib2.Opcode - -object VideoSpeedPatchFingerprint : MethodFingerprint( - opcodes = listOf(Opcode.FILL_ARRAY_DATA), - customFingerprint = { methodDef -> - methodDef.definingClass.endsWith("CustomVideoSpeedPatch;") && methodDef.name == "" - } -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt deleted file mode 100644 index 8f7401fbe..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/annotation/VideoIdCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.video.videoid.annotation - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class VideoIdCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt deleted file mode 100644 index da21078f2..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/patch/VideoIdPatch.kt +++ /dev/null @@ -1,58 +0,0 @@ -package app.revanced.patches.youtube.misc.video.videoid.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch -import app.revanced.patches.youtube.misc.video.videoid.annotation.VideoIdCompatibility -import app.revanced.patches.youtube.misc.video.videoid.fingerprint.VideoIdFingerprint -import org.jf.dexlib2.iface.instruction.OneRegisterInstruction - -@Name("video-id-hook") -@Description("Hooks to detect when the video id changes") -@VideoIdCompatibility -@Version("0.0.1") -@DependsOn([IntegrationsPatch::class]) -class VideoIdPatch : BytecodePatch( - listOf( - VideoIdFingerprint - ) -) { - override fun execute(context: BytecodeContext): PatchResult { - with(VideoIdFingerprint.result!!) { - insertMethod = mutableMethod - insertIndex = scanResult.patternScanResult!!.endIndex + 2 - - videoIdRegister = (insertMethod.instruction(insertIndex - 1) as OneRegisterInstruction).registerA - } - - return PatchResultSuccess() - } - - companion object { - private var videoIdRegister = 0 - private var insertIndex = 0 - - private lateinit var insertMethod: MutableMethod - - /** - * Adds an invoke-static instruction, called with the new id when the video changes - * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` - */ - fun injectCall( - methodDescriptor: String - ) = insertMethod.addInstructions( - insertIndex, // move-result-object offset - "invoke-static {v$videoIdRegister}, $methodDescriptor" - ) - } -} - diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt deleted file mode 100644 index 92f3ae0dd..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/annotations/CustomVideoBufferCompatibility.kt +++ /dev/null @@ -1,13 +0,0 @@ -package app.revanced.patches.youtube.misc.videobuffer.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility( - [Package( - "com.google.android.youtube", arrayOf("17.49.37") - )] -) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class CustomVideoBufferCompatibility diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt deleted file mode 100644 index 4562f93b3..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/videobuffer/patch/CustomVideoBufferPatch.kt +++ /dev/null @@ -1,137 +0,0 @@ -package app.revanced.patches.youtube.misc.videobuffer.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.InputType -import app.revanced.patches.shared.settings.preference.impl.PreferenceScreen -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.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 -import app.revanced.patches.youtube.misc.videobuffer.fingerprints.ReBufferFingerprint -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( - listOf( - MaxBufferFingerprint, PlaybackBufferFingerprint, ReBufferFingerprint - ) -) { - override fun execute(context: BytecodeContext): 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() - execReBuffer() - return PatchResultSuccess() - } - - private fun execMaxBuffer() { - val (method, result) = MaxBufferFingerprint.unwrap(true, -1) - val (index, register) = result - - method.addInstructions( - index + 1, """ - invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getMaxBuffer()I - move-result v$register - """ - ) - } - - private fun execPlaybackBuffer() { - val (method, result) = PlaybackBufferFingerprint.unwrap() - val (index, register) = result - - method.addInstructions( - index + 1, """ - invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getPlaybackBuffer()I - move-result v$register - """ - ) - } - - private fun execReBuffer() { - val (method, result) = ReBufferFingerprint.unwrap() - val (index, register) = result - - method.addInstructions( - index + 1, """ - invoke-static {}, Lapp/revanced/integrations/patches/VideoBufferPatch;->getReBuffer()I - move-result v$register - """ - ) - } - - private fun MethodFingerprint.unwrap( - forEndIndex: Boolean = false, - offset: Int = 0 - ): Pair> { - val result = this.result!! - val method = result.mutableMethod - val scanResult = result.scanResult.patternScanResult!! - val index = (if (forEndIndex) scanResult.endIndex else scanResult.startIndex) + offset - - val register = (method.instruction(index) as OneRegisterInstruction).registerA - - return method to (index to register) - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/legacy/fingerprint/LegacyVideoIdFingerprint.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/videoid/legacy/fingerprint/LegacyVideoIdFingerprint.kt index b688fb7a0..f69620b4a 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/videoid/fingerprint/VideoIdFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/legacy/fingerprint/LegacyVideoIdFingerprint.kt @@ -1,11 +1,11 @@ -package app.revanced.patches.youtube.misc.video.videoid.fingerprint +package app.revanced.patches.youtube.misc.videoid.legacy.fingerprint import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -object VideoIdFingerprint : MethodFingerprint( +object LegacyVideoIdFingerprint : MethodFingerprint( "V", AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, listOf("L"), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/legacy/patch/LegacyVideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/legacy/patch/LegacyVideoIdPatch.kt new file mode 100644 index 000000000..494c52c89 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/legacy/patch/LegacyVideoIdPatch.kt @@ -0,0 +1,60 @@ +package app.revanced.patches.youtube.misc.videoid.legacy.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patches.youtube.misc.videoid.legacy.fingerprint.LegacyVideoIdFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction + +@Name("video-id-hook-legacy") +@Description("Hook to detect when the video id changes (legacy)") +@YouTubeCompatibility +@Version("0.0.1") +class LegacyVideoIdPatch : BytecodePatch( + listOf( + LegacyVideoIdFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + result = LegacyVideoIdFingerprint.result!! + + insertMethod = result.mutableMethod + videoIdRegister = + (insertMethod.implementation!!.instructions[result.scanResult.patternScanResult!!.endIndex + 1] as OneRegisterInstruction).registerA + + offset++ // offset so setCurrentVideoId is called before any injected call + + return PatchResultSuccess() + } + + companion object { + private var offset = 2 + + private var videoIdRegister: Int = 0 + private lateinit var result: MethodFingerprintResult + private lateinit var insertMethod: MutableMethod + + /** + * Adds an invoke-static instruction, called with the new id when the video changes + * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` + */ + fun injectCall( + methodDescriptor: String + ) { + insertMethod.addInstructions( + result.scanResult.patternScanResult!!.endIndex + offset, // move-result-object offset + "invoke-static {v$videoIdRegister}, $methodDescriptor" + ) + } + } +} + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/MainstreamVideoIdFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/MainstreamVideoIdFingerprint.kt new file mode 100644 index 000000000..55c6cfa79 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/MainstreamVideoIdFingerprint.kt @@ -0,0 +1,29 @@ +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object MainstreamVideoIdFingerprint : MethodFingerprint( + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L"), + listOf( + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.IF_EQZ, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT, + Opcode.INVOKE_INTERFACE, + Opcode.MOVE_RESULT_OBJECT + ), + null, + { it.definingClass.endsWith("SubtitlesOverlayPresenter;") } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerControllerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerControllerFingerprint.kt new file mode 100644 index 000000000..315229dc5 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerControllerFingerprint.kt @@ -0,0 +1,9 @@ +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object PlayerControllerFingerprint : MethodFingerprint( + customFingerprint = { methodDef -> + methodDef.definingClass == "Lapp/revanced/integrations/sponsorblock/PlayerController;" && methodDef.name == "setSponsorBarRect" + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerControllerSetTimeReferenceFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerControllerSetTimeReferenceFingerprint.kt index fe0355d68..a63a695aa 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerControllerSetTimeReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerControllerSetTimeReferenceFingerprint.kt @@ -1,8 +1,6 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints - +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - import org.jf.dexlib2.Opcode object PlayerControllerSetTimeReferenceFingerprint : MethodFingerprint( diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerInitFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerInitFingerprint.kt similarity index 75% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerInitFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerInitFingerprint.kt index 7e6485525..b35e1df5c 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/PlayerInitFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/PlayerInitFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints - +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/RepeatListenerFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/RepeatListenerFingerprint.kt new file mode 100644 index 000000000..5b9985516 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/RepeatListenerFingerprint.kt @@ -0,0 +1,21 @@ +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object RepeatListenerFingerprint : MethodFingerprint( + returnType = "Z", + access = AccessFlags.PUBLIC or AccessFlags.FINAL, + opcodes = listOf( + Opcode.INVOKE_VIRTUAL_RANGE, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.CHECK_CAST, + Opcode.CONST_WIDE_32 + ), + strings = listOf( + "ppoobsa" + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/SeekFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/SeekFingerprint.kt similarity index 70% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/SeekFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/SeekFingerprint.kt index 8f2ba9663..256007ec5 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/SeekFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/SeekFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints - +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/VideoTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/VideoTimeFingerprint.kt new file mode 100644 index 000000000..febb57515 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/VideoTimeFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VideoTimeFingerprint : MethodFingerprint ( + "V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("J", "J", "J", "J", "I", "L"), listOf( + Opcode.INVOKE_DIRECT, + Opcode.IPUT_WIDE, + Opcode.IPUT_WIDE, + Opcode.IPUT_WIDE, + Opcode.IPUT_WIDE, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoTimeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/VideoTimeParentFingerprint.kt similarity index 52% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoTimeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/VideoTimeParentFingerprint.kt index d04b75377..9987110c8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/information/fingerprints/VideoTimeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/fingerprint/VideoTimeParentFingerprint.kt @@ -1,8 +1,7 @@ -package app.revanced.patches.youtube.misc.video.information.fingerprints - +package app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint -object VideoTimeFingerprint : MethodFingerprint( +object VideoTimeParentFingerprint : MethodFingerprint( strings = listOf("MedialibPlayerTimeInfo{currentPositionMillis=") ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/patch/MainstreamVideoIdPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/patch/MainstreamVideoIdPatch.kt new file mode 100644 index 000000000..441af1efe --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/videoid/mainstream/patch/MainstreamVideoIdPatch.kt @@ -0,0 +1,214 @@ +package app.revanced.patches.youtube.misc.videoid.mainstream.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.removeInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.extensions.or +import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch +import app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.timebar.HookTimebarPatch +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.builder.MutableMethodImplementation +import org.jf.dexlib2.iface.instruction.formats.Instruction21c +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodParameter +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.util.MethodUtil + +@Name("video-id-hook-mainstream") +@Description("Hook to detect when the video id changes (mainstream)") +@YouTubeCompatibility +@Version("0.0.1") +@DependsOn( + [ + HookTimebarPatch::class, + PlayerTypeHookPatch::class + ] +) +class MainstreamVideoIdPatch : BytecodePatch( + listOf( + MainstreamVideoIdFingerprint, + PlayerControllerFingerprint, + PlayerControllerSetTimeReferenceFingerprint, + PlayerInitFingerprint, + RepeatListenerFingerprint, + SeekFingerprint, + VideoTimeFingerprint, + VideoTimeParentFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val VideoInformation = "$VIDEO_PATH/VideoInformation;" + + val RepeatListenerResult = RepeatListenerFingerprint.result!! + val RepeatListenerMethod = RepeatListenerResult.mutableMethod + val removeIndex = RepeatListenerResult.scanResult.patternScanResult!!.startIndex + + // RepeatListenerMethod.removeInstruction(removeIndex) + RepeatListenerMethod.removeInstruction(removeIndex - 1) + + with(PlayerInitFingerprint.result!!) { + PlayerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) } + + // seek method + val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method + + // create helper method + val seekHelperMethod = ImmutableMethod( + seekFingerprintResultMethod.definingClass, + "seekTo", + listOf(ImmutableMethodParameter("J", null, "time")), + "Z", + AccessFlags.PUBLIC or AccessFlags.FINAL, + null, null, + MutableMethodImplementation(4) + ).toMutable() + + // get enum type for the seek helper method + val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString() + + // insert helper method instructions + seekHelperMethod.addInstructions( + 0, + """ + sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType + invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z + move-result p1 + return p1 + """ + ) + + // add the seekTo method to the class for the integrations to call + mutableClass.methods.add(seekHelperMethod) + } + + val VideoTimeParentResult = VideoTimeParentFingerprint.result!! + VideoTimeFingerprint.resolve(context, VideoTimeParentResult.classDef) + val VideoTimeMethod = VideoTimeFingerprint.result!!.mutableMethod + VideoTimeMethod.addInstruction( + 0, + "invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTimeHighPrecision(J)V" + ) + + /* + Set current video time + */ + val referenceResult = PlayerControllerSetTimeReferenceFingerprint.result!! + val PlayerControllerSetTimeMethod = + context.toMethodWalker(referenceResult.method) + .nextMethod(referenceResult.scanResult.patternScanResult!!.startIndex, true) + .getMethod() as MutableMethod + PlayerControllerSetTimeMethod.addInstruction( + 2, + "invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTime(J)V" + ) + + val EmptyColorMethod = HookTimebarPatch.EmptyColorFingerprintResult.mutableMethod + val EmptyColorMethodInstructions = EmptyColorMethod.implementation!!.instructions + + val methodReference = + HookTimebarPatch.TimbarFingerprintResult.method.let { method -> + (method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as MethodReference + } + + for ((index, instruction) in EmptyColorMethodInstructions.withIndex()) { + if (instruction.opcode != Opcode.CHECK_CAST) continue + val primaryRegister = (instruction as Instruction21c).registerA + 1 + val secondaryRegister = primaryRegister + 1 + EmptyColorMethod.addInstructions( + index, """ + invoke-virtual {p0}, $methodReference + move-result-wide v$primaryRegister + invoke-static {v$primaryRegister, v$secondaryRegister}, $VideoInformation->setCurrentVideoLength(J)V + """ + ) + break + } + + val reactReference = + ((EmptyColorMethodInstructions.elementAt(EmptyColorMethodInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name + + val PlayerContrallerResult = PlayerControllerFingerprint.result!! + val PlayerContrallerMethod = PlayerContrallerResult.mutableMethod + val PlayerContrallerInstructions = PlayerContrallerMethod.implementation!!.instructions + + /* + Get the instance of the seekbar rectangle + */ + for ((index, instruction) in PlayerContrallerInstructions.withIndex()) { + if (instruction.opcode != Opcode.CONST_STRING) continue + val register = (instruction as OneRegisterInstruction).registerA + PlayerContrallerMethod.replaceInstruction( + index, + "const-string v$register, \"$reactReference\"" + ) + break + } + + + InsertResult = MainstreamVideoIdFingerprint.result!! + InsertMethod = InsertResult.mutableMethod + InsertIndex = InsertResult.scanResult.patternScanResult!!.endIndex + + videoIdRegister = + (InsertMethod.implementation!!.instructions[InsertIndex] as OneRegisterInstruction).registerA + + injectCall("$VideoInformation->setCurrentVideoId(Ljava/lang/String;)V") + injectCallonCreate("$VideoInformation", "onCreate") + + offset++ // offset so setCurrentVideoId is called before any injected call + + return PatchResultSuccess() + } + + companion object { + private var offset = 1 + + private var videoIdRegister: Int = 0 + private var InsertIndex: Int = 0 + private lateinit var InsertResult: MethodFingerprintResult + private lateinit var InsertMethod: MutableMethod + private lateinit var PlayerInitMethod: MutableMethod + + /** + * Adds an invoke-static instruction, called with the new id when the video changes + * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` + */ + fun injectCall( + methodDescriptor: String + ) { + InsertMethod.addInstructions( + InsertIndex + offset, // move-result-object offset + "invoke-static {v$videoIdRegister}, $methodDescriptor" + ) + } + + fun injectCallonCreate(MethodClass: String, MethodName: String) = + PlayerInitMethod.addInstruction( + 4, + "invoke-static {v0}, $MethodClass->$MethodName(Ljava/lang/Object;)V" + ) + } +} + diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/annotations/ZoomHapticsCompatibility.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/annotations/ZoomHapticsCompatibility.kt deleted file mode 100644 index 86819cdd8..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/annotations/ZoomHapticsCompatibility.kt +++ /dev/null @@ -1,9 +0,0 @@ -package app.revanced.patches.youtube.misc.zoomhaptics.annotations - -import app.revanced.patcher.annotation.Compatibility -import app.revanced.patcher.annotation.Package - -@Compatibility([Package("com.google.android.youtube")]) -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.RUNTIME) -internal annotation class ZoomHapticsCompatibility \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/fingerprints/ZoomHapticsFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/fingerprints/ZoomHapticsFingerprint.kt deleted file mode 100644 index 493db9c4e..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/fingerprints/ZoomHapticsFingerprint.kt +++ /dev/null @@ -1,8 +0,0 @@ -package app.revanced.patches.youtube.misc.zoomhaptics.fingerprints -import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - -object ZoomHapticsFingerprint : MethodFingerprint( - strings = listOf( - "Failed to haptics vibrate for video zoom" - ) -) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt deleted file mode 100644 index 89cccda3c..000000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/zoomhaptics/patch/ZoomHapticsPatch.kt +++ /dev/null @@ -1,54 +0,0 @@ -package app.revanced.patches.youtube.misc.zoomhaptics.patch - -import app.revanced.patcher.annotation.Description -import app.revanced.patcher.annotation.Name -import app.revanced.patcher.annotation.Version -import app.revanced.patcher.data.BytecodeContext -import app.revanced.patcher.extensions.addInstructions -import app.revanced.patcher.extensions.instruction -import app.revanced.patcher.patch.BytecodePatch -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.smali.ExternalLabel -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.shared.settings.preference.impl.SwitchPreference -import app.revanced.patches.youtube.misc.zoomhaptics.annotations.ZoomHapticsCompatibility -import app.revanced.patches.youtube.misc.zoomhaptics.fingerprints.ZoomHapticsFingerprint - -@Patch -@Name("disable-zoom-haptics") -@Description("Disables haptics when zooming.") -@DependsOn([SettingsPatch::class]) -@ZoomHapticsCompatibility -@Version("0.0.1") -class ZoomHapticsPatch : BytecodePatch( - listOf(ZoomHapticsFingerprint) -) { - override fun execute(context: BytecodeContext): PatchResult { - SettingsPatch.PreferenceScreen.MISC.addPreferences( - SwitchPreference( - "revanced_disable_zoom_haptics", - StringResource("revanced_disable_zoom_haptics_title", "Disable zoom haptics"), - true, - StringResource("revanced_disable_zoom_haptics_summary_on", "Haptics are disabled"), - StringResource("revanced_disable_zoom_haptics_summary_off", "Haptics are enabled") - ) - ) - - val zoomHapticsFingerprintMethod = ZoomHapticsFingerprint.result!!.mutableMethod - - zoomHapticsFingerprintMethod.addInstructions( - 0, """ - invoke-static { }, Lapp/revanced/integrations/patches/ZoomHapticsPatch;->shouldVibrate()Z - move-result v0 - if-nez v0, :vibrate - return-void - """, listOf(ExternalLabel("vibrate", zoomHapticsFingerprintMethod.instruction(0))) - ) - - return PatchResultSuccess() - } -} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/fingerprints/SwipeControlsHostActivityFingerprint.kt similarity index 80% rename from src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/fingerprints/SwipeControlsHostActivityFingerprint.kt index 25e3ada23..b8043b007 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/fingerprints/SwipeControlsHostActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/fingerprints/SwipeControlsHostActivityFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.youtube.interaction.swipecontrols.fingerprints - +package app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/fingerprints/WatchWhileActivityFingerprint.kt similarity index 77% rename from src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/fingerprints/WatchWhileActivityFingerprint.kt index b10c5e23e..e1a0e17c5 100644 --- a/src/main/kotlin/app/revanced/patches/shared/fingerprints/WatchWhileActivityFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/fingerprints/WatchWhileActivityFingerprint.kt @@ -1,5 +1,4 @@ -package app.revanced.patches.shared.fingerprints - +package app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/patch/SwipeControlsBytecodePatch.kt similarity index 67% rename from src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/patch/SwipeControlsBytecodePatch.kt index 22f94b83f..bd0c0d313 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/interaction/swipecontrols/patch/bytecode/SwipeControlsBytecodePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/bytecode/patch/SwipeControlsBytecodePatch.kt @@ -1,42 +1,40 @@ -package app.revanced.patches.youtube.interaction.swipecontrols.patch.bytecode +package app.revanced.patches.youtube.swipe.swipecontrols.bytecode.patch -import app.revanced.extensions.transformMethods import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patcher.util.TypeUtil.traverseClassHierarchy import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable -import app.revanced.patches.shared.fingerprints.WatchWhileActivityFingerprint -import app.revanced.patches.youtube.interaction.swipecontrols.annotation.SwipeControlsCompatibility -import app.revanced.patches.youtube.interaction.swipecontrols.fingerprints.SwipeControlsHostActivityFingerprint -import app.revanced.patches.youtube.interaction.swipecontrols.patch.resource.SwipeControlsResourcePatch -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patcher.util.TypeUtil.traverseClassHierarchy +import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.SwipeControlsHostActivityFingerprint +import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.WatchWhileActivityFingerprint +import app.revanced.patches.youtube.misc.hdrbrightness.bytecode.patch.HDRBrightnessBytecodePatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.extensions.transformMethods import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.immutable.ImmutableMethod -@Patch -@Name("swipe-controls") -@Description("Adds volume and brightness swipe controls.") -@SwipeControlsCompatibility +@Name("swipe-controls-bytecode-patch") +@YouTubeCompatibility @Version("0.0.3") @DependsOn( [ - IntegrationsPatch::class, - PlayerTypeHookPatch::class, - SwipeControlsResourcePatch::class + HDRBrightnessBytecodePatch::class, + PlayerTypeHookPatch::class ] ) class SwipeControlsBytecodePatch : BytecodePatch( listOf( - WatchWhileActivityFingerprint, - SwipeControlsHostActivityFingerprint + SwipeControlsHostActivityFingerprint, + WatchWhileActivityFingerprint ) ) { override fun execute(context: BytecodeContext): PatchResult { @@ -63,6 +61,7 @@ class SwipeControlsBytecodePatch : BytecodePatch( ).toMutable() } } + return PatchResultSuccess() } } \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/resource/patch/SwipeControlsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/resource/patch/SwipeControlsPatch.kt new file mode 100644 index 000000000..37222d88c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/swipe/swipecontrols/resource/patch/SwipeControlsPatch.kt @@ -0,0 +1,60 @@ +package app.revanced.patches.youtube.swipe.swipecontrols.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.patch.SwipeControlsBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources + +@Patch +@Name("swipe-controls") +@Description("Adds volume and brightness swipe controls.") +@DependsOn( + [ + SettingsPatch::class, + SwipeControlsBytecodePatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class SwipeControlsPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_SETTINGS", + "PREFERENCE: SWIPE_SETTINGS", + "SETTINGS: SWIPE_CONTROLS" + ) + + ResourceHelper.patchSuccess( + context, + "swipe-controls" + ) + + context.copyResources( + "youtube/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() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/SpeedArrayGeneratorFingerprint.kt similarity index 82% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/SpeedArrayGeneratorFingerprint.kt index e4e336880..97abdad0e 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedArrayGeneratorFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/SpeedArrayGeneratorFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints +package app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod @@ -10,7 +10,8 @@ import org.jf.dexlib2.Opcode object SpeedArrayGeneratorFingerprint : MethodFingerprint( "[L", AccessFlags.PUBLIC or AccessFlags.STATIC, - opcodes = listOf( + null, + listOf( Opcode.IF_NEZ, Opcode.SGET_OBJECT, Opcode.GOTO, @@ -18,5 +19,5 @@ object SpeedArrayGeneratorFingerprint : MethodFingerprint( Opcode.MOVE_RESULT_OBJECT, Opcode.IGET_OBJECT, ), - strings = listOf("0.0#") + listOf("0.0#") ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/SpeedLimiterFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/SpeedLimiterFingerprint.kt index 4cb98cd4d..0d2901873 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/fingerprints/SpeedLimiterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/SpeedLimiterFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.fingerprints +package app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/VideoSpeedEntriesFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/VideoSpeedEntriesFingerprint.kt new file mode 100644 index 000000000..7393d537b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/fingerprints/VideoSpeedEntriesFingerprint.kt @@ -0,0 +1,11 @@ +package app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.Opcode + +object VideoSpeedEntriesFingerprint : MethodFingerprint( + opcodes = listOf(Opcode.FILL_ARRAY_DATA), + customFingerprint = { methodDef -> + methodDef.definingClass.endsWith("VideoSpeedEntries;") && methodDef.name == "" + } +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/patch/CustomVideoSpeedBytecodePatch.kt similarity index 50% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/patch/CustomVideoSpeedBytecodePatch.kt index 1b76883b7..e7e020cac 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/speed/custom/patch/CustomVideoSpeedPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/bytecode/patch/CustomVideoSpeedBytecodePatch.kt @@ -1,44 +1,51 @@ -package app.revanced.patches.youtube.misc.video.speed.custom.patch +package app.revanced.patches.youtube.video.customspeed.bytecode.patch -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.replaceInstruction -import app.revanced.patcher.patch.* import app.revanced.patcher.patch.annotations.DependsOn -import app.revanced.patcher.patch.annotations.Patch -import app.revanced.patches.youtube.misc.video.speed.custom.annotations.CustomPlaybackSpeedCompatibility -import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedArrayGeneratorFingerprint -import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.SpeedLimiterFingerprint -import app.revanced.patches.youtube.misc.video.speed.custom.fingerprints.VideoSpeedPatchFingerprint -import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints.* +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH import org.jf.dexlib2.builder.instruction.BuilderArrayPayload import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.reference.FieldReference import org.jf.dexlib2.iface.reference.MethodReference -import java.util.stream.DoubleStream -import kotlin.math.roundToInt -@Patch -@Name("custom-video-speed") -@Description("Adds more video speed options.") -@DependsOn([IntegrationsPatch::class]) -@CustomPlaybackSpeedCompatibility +@Name("custom-speed-bytecode-patch") +@DependsOn([PatchOptions::class]) +@YouTubeCompatibility @Version("0.0.1") -class CustomVideoSpeedPatch : BytecodePatch( +class CustomVideoSpeedBytecodePatch : BytecodePatch( listOf( - SpeedArrayGeneratorFingerprint, SpeedLimiterFingerprint, VideoSpeedPatchFingerprint + SpeedArrayGeneratorFingerprint, + SpeedLimiterFingerprint, + VideoSpeedEntriesFingerprint ) ) { + private companion object { + const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoSpeedPatch;" + const val INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoSpeedEntries;" + } override fun execute(context: BytecodeContext): PatchResult { - val speedLimitMin = minVideoSpeed!!.toFloat() - val speedLimitMax = maxVideoSpeed!!.toFloat().coerceAtLeast(speedLimitMin) - val speedsGranularity = videoSpeedsGranularity!!.toFloat() + var speed = PatchOptions.CustomSpeedArrays + val splits = speed!!.replace(" ","").split(",") + if (splits.count() < 1) throw IllegalArgumentException("Invalid speed elements") + val videoSpeedsArray = splits.map { it.toFloat().toRawBits() } val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!! val arrayGenMethodImpl = arrayGenMethod.implementation!! @@ -51,24 +58,31 @@ class CustomVideoSpeedPatch : BytecodePatch( val sizeCallResultRegister = (arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA - arrayGenMethod.replaceInstruction( - sizeCallIndex + 1, - "const/4 v$sizeCallResultRegister, 0x0" + arrayGenMethod.addInstructions( + sizeCallIndex + 2, + """ + invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z + move-result v9 + if-eqz v9, :defaultspeed + const/4 v$sizeCallResultRegister, 0x0 + """, listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(sizeCallIndex + 2))) ) + val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex() .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 } val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA - val videoSpeedsArrayType = "Lapp/revanced/integrations/patches/playback/speed/CustomVideoSpeedPatch;->videoSpeeds:[F" + val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F" arrayGenMethod.addInstructions( arrayLengthConstIndex + 1, """ + if-eqz v9, :defaultspeed sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination - """ + """, listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(arrayLengthConstIndex + 1))) ) val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex() @@ -80,14 +94,20 @@ class CustomVideoSpeedPatch : BytecodePatch( val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA - arrayGenMethod.replaceInstruction( - originalArrayFetchIndex, - "sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType" + arrayGenMethod.addInstructions( + originalArrayFetchIndex + 1, + """ + if-eqz v9, :defaultspeed + sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType + """, listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(originalArrayFetchIndex + 1))) ) - val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!! + val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!; val limiterMethodImpl = limiterMethod.implementation!! + val speedLimitMin = 0.0f + val speedLimitMax = 100f + val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex() .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex() @@ -107,37 +127,15 @@ class CustomVideoSpeedPatch : BytecodePatch( "const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}" ) - val constructorResult = VideoSpeedPatchFingerprint.result!! + val constructorResult = VideoSpeedEntriesFingerprint.result!! val constructor = constructorResult.mutableMethod val implementation = constructor.implementation!! - val stepsGranularity = 8F - val step = speedLimitMax - .minus(speedLimitMin) // calculate the range of the speeds - .div(speedsGranularity) - .times(stepsGranularity) - .roundToInt() - .div(stepsGranularity)// round to nearest multiple of stepsGranularity - .coerceAtLeast(1 / stepsGranularity) // ensure steps are at least 1/8th of the step granularity - - val videoSpeedsArray = buildList { - DoubleStream - .iterate(speedLimitMin.toDouble()) { it + step } // create a stream of speeds - .let { speedStream -> - for (speed in speedStream) { - if (speed > speedLimitMax) break - add(speed.toFloat().toRawBits()) - } - } - } - - // adjust the new array of speeds size constructor.replaceInstruction( 0, "const/16 v0, ${videoSpeedsArray.size}" ) - // create the payload with the new speeds val arrayPayloadIndex = implementation.instructions.size - 1 implementation.replaceInstruction( arrayPayloadIndex, @@ -149,47 +147,4 @@ class CustomVideoSpeedPatch : BytecodePatch( return PatchResultSuccess() } - - companion object : OptionsContainer() { - private fun String?.validate(max: Int? = null) = this?.toFloatOrNull() != null && - toFloat().let { float -> - float > 0 && max?.let { max -> float <= max } ?: true - } - - val videoSpeedsGranularity by option( - PatchOption.StringOption( - "granularity", - "16", - "Video speed granularity", - "The granularity of the video speeds. The higher the value, the more speeds will be available.", - true - ) { - it.validate() - } - ) - - val minVideoSpeed by option( - PatchOption.StringOption( - "min", - "0.25", - "Minimum video speed", - "The minimum video speed.", - true - ) { - it.validate() - } - ) - - val maxVideoSpeed by option( - PatchOption.StringOption( - "max", - "5.0", - "Maximum video speed", - "The maximum video speed. Must be greater than the minimum video speed and smaller than 5.", - true - ) { - it.validate(5) - } - ) - } } diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/resource/patch/CustomVideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/resource/patch/CustomVideoSpeedPatch.kt new file mode 100644 index 000000000..4492a0094 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/customspeed/resource/patch/CustomVideoSpeedPatch.kt @@ -0,0 +1,70 @@ +package app.revanced.patches.youtube.video.customspeed.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.video.customspeed.bytecode.patch.CustomVideoSpeedBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.patches.options.PatchOptions +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode +import java.nio.file.Files +import java.nio.file.StandardCopyOption + +@Patch +@Name("custom-video-speed") +@Description("Adds more video speed options.") +@DependsOn( + [ + CustomVideoSpeedBytecodePatch::class, + PatchOptions::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class CustomVideoSpeedPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + * Copy arrays + */ + context.copyXmlNode("youtube/speed/host", "values/arrays.xml", "resources") + + var speed = PatchOptions.CustomSpeedArrays + ?: return PatchResultError("Invalid video speed array.") + + val splits = speed.replace(" ","").split(",") + if (splits.count() < 1) throw IllegalArgumentException("Invalid speed elements") + val speedElements = splits.map { it } + for (index in 0 until splits.count()) { + ResourceHelper.addEntryValues(context, speedElements[index]) + ResourceHelper.addEntries(context, speedElements[index] + "x") + } + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: VIDEO_SETTINGS", + "SETTINGS: CUSTOM_VIDEO_SPEED" + ) + + ResourceHelper.patchSuccess( + context, + "custom-video-speed" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoQualityReferenceFingerprint.kt similarity index 83% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoQualityReferenceFingerprint.kt index 3ea366f78..ae6cdc4c8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualityReferenceFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoQualityReferenceFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.misc.video.quality.fingerprints +package app.revanced.patches.youtube.video.quality.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoQualitySetterFingerprint.kt similarity index 87% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoQualitySetterFingerprint.kt index db1853c17..92c86bbf8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoQualitySetterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoQualitySetterFingerprint.kt @@ -1,5 +1,4 @@ - -package app.revanced.patches.youtube.misc.video.quality.fingerprints +package app.revanced.patches.youtube.video.quality.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoUserQualityChangeFingerprint.kt similarity index 86% rename from src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoUserQualityChangeFingerprint.kt index 2575d5d3d..811c0a6f2 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/video/quality/fingerprints/VideoUserQualityChangeFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/fingerprints/VideoUserQualityChangeFingerprint.kt @@ -1,9 +1,7 @@ - -package app.revanced.patches.youtube.misc.video.quality.fingerprints +package app.revanced.patches.youtube.video.quality.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint - import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/patch/VideoQualityBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/patch/VideoQualityBytecodePatch.kt new file mode 100644 index 000000000..c95c96cb3 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/bytecode/patch/VideoQualityBytecodePatch.kt @@ -0,0 +1,71 @@ +package app.revanced.patches.youtube.video.quality.bytecode.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQualityReferenceFingerprint +import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQualitySetterFingerprint +import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoUserQualityChangeFingerprint +import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference + +@Name("default-video-quality-bytecode-patch") +@DependsOn([LegacyVideoIdPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class VideoQualityBytecodePatch : BytecodePatch( + listOf( + VideoQualitySetterFingerprint + ) +) { + private companion object { + const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoQualityPatch;" + } + override fun execute(context: BytecodeContext): PatchResult { + val setterMethod = VideoQualitySetterFingerprint.result!! + + VideoUserQualityChangeFingerprint.resolve(context, setterMethod.classDef) + val userQualityResult = VideoUserQualityChangeFingerprint.result!! + + VideoQualityReferenceFingerprint.resolve(context, setterMethod.classDef) + val qualityFieldReference = + VideoQualityReferenceFingerprint.result!!.method.let { method -> + (method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference + } + + LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + + val qIndexMethodName = + context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name + + setterMethod.mutableMethod.addInstructions( + 0, + """ + iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type} + const-string v1, "$qIndexMethodName" + invoke-static {p1, p2, v0, v1}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I + move-result p2 + """, + ) + + userQualityResult.mutableMethod.addInstruction( + 0, + "invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V" + ) + + return PatchResultSuccess() + } +} diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/quality/resource/patch/VideoQualityPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/quality/resource/patch/VideoQualityPatch.kt new file mode 100644 index 000000000..ebf23b3db --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/quality/resource/patch/VideoQualityPatch.kt @@ -0,0 +1,56 @@ +package app.revanced.patches.youtube.video.quality.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.video.quality.bytecode.patch.VideoQualityBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode + +@Patch +@Name("default-video-quality") +@Description("Adds ability to set default video quality settings.") +@DependsOn( + [ + VideoQualityBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class VideoQualityPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + * Copy arrays + */ + + context.copyXmlNode("youtube/quality/host", "values/arrays.xml", "resources") + + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: VIDEO_SETTINGS", + "SETTINGS: DEFAULT_VIDEO_QUALITY" + ) + + ResourceHelper.patchSuccess( + context, + "default-video-quality" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedReferenceFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedReferenceFingerprint.kt new file mode 100644 index 000000000..f140abdcb --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedReferenceFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.youtube.video.speed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VideoSpeedReferenceFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( + Opcode.IPUT_OBJECT, Opcode.RETURN_VOID + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSetterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSetterFingerprint.kt new file mode 100644 index 000000000..1d7644dd1 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoSpeedSetterFingerprint.kt @@ -0,0 +1,19 @@ +package app.revanced.patches.youtube.video.speed.bytecode.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object VideoSpeedSetterFingerprint : MethodFingerprint( + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("[L", "I"), + listOf( + Opcode.MOVE_RESULT, + Opcode.IF_EQZ, + Opcode.INVOKE_VIRTUAL, + Opcode.INVOKE_STATIC, + Opcode.INVOKE_VIRTUAL, + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/DrawActionBarFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoUserSpeedChangeFingerprint.kt similarity index 56% rename from src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/DrawActionBarFingerprint.kt rename to src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoUserSpeedChangeFingerprint.kt index 5ea1ffa3f..5ae0f6e50 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/widesearchbar/fingerprints/DrawActionBarFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/fingerprints/VideoUserSpeedChangeFingerprint.kt @@ -1,27 +1,27 @@ -package app.revanced.patches.youtube.layout.widesearchbar.fingerprints +package app.revanced.patches.youtube.video.speed.bytecode.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.Opcode -object DrawActionBarFingerprint : MethodFingerprint( +object VideoUserSpeedChangeFingerprint : MethodFingerprint( "V", - AccessFlags.PRIVATE or AccessFlags.FINAL, - listOf("I", "I"), + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L","L","I","J"), listOf( + Opcode.IGET_OBJECT, + Opcode.IF_EQZ, + Opcode.IF_EQZ, + Opcode.IGET, + Opcode.CHECK_CAST, + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.IGET_OBJECT, Opcode.INVOKE_STATIC, Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.SGET_OBJECT, Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - ), + Opcode.RETURN_VOID + ) ) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt new file mode 100644 index 000000000..33c40851c --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/bytecode/patch/VideoSpeedBytecodePatch.kt @@ -0,0 +1,112 @@ +package app.revanced.patches.youtube.video.speed.bytecode.patch + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable +import app.revanced.patcher.util.smali.toInstructions +import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoSpeedReferenceFingerprint +import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoSpeedSetterFingerprint +import app.revanced.patches.youtube.video.speed.bytecode.fingerprints.VideoUserSpeedChangeFingerprint +import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.bytecode.BytecodeHelper +import app.revanced.shared.util.integrations.Constants.VIDEO_PATH +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.immutable.ImmutableMethod +import org.jf.dexlib2.immutable.ImmutableMethodImplementation +import org.jf.dexlib2.immutable.ImmutableMethodParameter + +@Name("default-video-speed-bytecode-patch") +@DependsOn([LegacyVideoIdPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class VideoSpeedBytecodePatch : BytecodePatch( + listOf( + VideoSpeedSetterFingerprint, VideoUserSpeedChangeFingerprint + ) +) { + private companion object { + const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR = + "$VIDEO_PATH/VideoSpeedPatch;" + } + override fun execute(context: BytecodeContext): PatchResult { + + val userSpeedResult = VideoUserSpeedChangeFingerprint.result!! + val userSpeedMutableMethod = userSpeedResult.mutableMethod + + val setterResult = VideoSpeedSetterFingerprint.result!! + val setterMutableMethod = setterResult.mutableMethod + + VideoUserSpeedChangeFingerprint.resolve(context, setterResult.classDef) + val FirstReference = + VideoUserSpeedChangeFingerprint.result!!.method.let { method -> + (method.implementation!!.instructions.elementAt(5) as ReferenceInstruction).reference as FieldReference + } + val SecondReference = + VideoUserSpeedChangeFingerprint.result!!.method.let { method -> + (method.implementation!!.instructions.elementAt(10) as ReferenceInstruction).reference as FieldReference + } + val ThirdReference = + VideoUserSpeedChangeFingerprint.result!!.method.let { method -> + (method.implementation!!.instructions.elementAt(11) as ReferenceInstruction).reference as MethodReference + } + + userSpeedMutableMethod.addInstruction( + 0, "invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->userChangedSpeed()V" + ) + + setterMutableMethod.addInstructions( + 0, + """ + invoke-static {p1, p2}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue([Ljava/lang/Object;I)F + move-result v0 + invoke-direct {p0, v0}, ${setterResult.classDef.type}->overrideSpeed(F)V + """, + ) + + val classDef = userSpeedResult.mutableClass + classDef.methods.add( + ImmutableMethod( + classDef.type, + "overrideSpeed", + listOf(ImmutableMethodParameter("F", null, null)), + "V", + AccessFlags.PRIVATE or AccessFlags.PRIVATE, + null, + null, + ImmutableMethodImplementation( + 4, """ + const/4 v0, 0x0 + cmpg-float v0, v3, v0 + if-gez v0, :cond_0 + return-void + :cond_0 + iget-object v0, v2, ${setterResult.classDef.type}->${FirstReference.name}:${FirstReference.type} + check-cast v0, ${SecondReference.definingClass} + iget-object v1, v0, ${SecondReference.definingClass}->${SecondReference.name}:${SecondReference.type} + invoke-virtual {v1, v3}, $ThirdReference + return-void + """.toInstructions(), null, null + ) + ).toMutable() + ) + + LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V") + + BytecodeHelper.patchStatus(context, "VideoSpeed") + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/video/speed/resource/patch/VideoSpeedPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/video/speed/resource/patch/VideoSpeedPatch.kt new file mode 100644 index 000000000..2ad144767 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/video/speed/resource/patch/VideoSpeedPatch.kt @@ -0,0 +1,48 @@ +package app.revanced.patches.youtube.video.speed.resource.patch + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.patches.youtube.video.speed.bytecode.patch.VideoSpeedBytecodePatch +import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.util.resources.ResourceHelper + +@Patch +@Name("default-video-speed") +@Description("Adds ability to set default video speed settings.") +@DependsOn( + [ + VideoSpeedBytecodePatch::class, + SettingsPatch::class + ] +) +@YouTubeCompatibility +@Version("0.0.1") +class VideoSpeedPatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + /* + add settings + */ + ResourceHelper.addSettings( + context, + "PREFERENCE_CATEGORY: REVANCED_EXTENDED_SETTINGS", + "PREFERENCE: VIDEO_SETTINGS", + "SETTINGS: DEFAULT_VIDEO_SPEED" + ) + + ResourceHelper.patchSuccess( + context, + "default-video-speed" + ) + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt b/src/main/kotlin/app/revanced/shared/annotation/YouTubeCompatibility.kt similarity index 71% rename from src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt rename to src/main/kotlin/app/revanced/shared/annotation/YouTubeCompatibility.kt index daf82783c..8cc92f4fb 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/ad/video/annotations/VideoAdsCompatibility.kt +++ b/src/main/kotlin/app/revanced/shared/annotation/YouTubeCompatibility.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.ad.video.annotations +package app.revanced.shared.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package @@ -10,5 +10,5 @@ import app.revanced.patcher.annotation.Package ) @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) -internal annotation class VideoAdsCompatibility +internal annotation class YouTubeCompatibility diff --git a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/annotations/AudioAdsCompatibility.kt b/src/main/kotlin/app/revanced/shared/annotation/YouTubeMusicCompatibility.kt similarity index 52% rename from src/main/kotlin/app/revanced/patches/twitch/ad/audio/annotations/AudioAdsCompatibility.kt rename to src/main/kotlin/app/revanced/shared/annotation/YouTubeMusicCompatibility.kt index 0e39cb8d3..da278a9b5 100644 --- a/src/main/kotlin/app/revanced/patches/twitch/ad/audio/annotations/AudioAdsCompatibility.kt +++ b/src/main/kotlin/app/revanced/shared/annotation/YouTubeMusicCompatibility.kt @@ -1,10 +1,10 @@ -package app.revanced.patches.twitch.ad.audio.annotations +package app.revanced.shared.annotation import app.revanced.patcher.annotation.Compatibility import app.revanced.patcher.annotation.Package -@Compatibility([Package("tv.twitch.android.app")]) +@Compatibility([Package("com.google.android.apps.youtube.music")]) @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) -internal annotation class AudioAdsCompatibility +internal annotation class YouTubeMusicCompatibility diff --git a/src/main/kotlin/app/revanced/extensions/Extensions.kt b/src/main/kotlin/app/revanced/shared/extensions/Extensions.kt similarity index 58% rename from src/main/kotlin/app/revanced/extensions/Extensions.kt rename to src/main/kotlin/app/revanced/shared/extensions/Extensions.kt index 7c70f90c6..8fb473b25 100644 --- a/src/main/kotlin/app/revanced/extensions/Extensions.kt +++ b/src/main/kotlin/app/revanced/shared/extensions/Extensions.kt @@ -1,14 +1,41 @@ -package app.revanced.extensions +package app.revanced.shared.extensions import app.revanced.patcher.extensions.MethodFingerprintExtensions.name import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.patcher.util.smali.toInstruction +import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH +import app.revanced.shared.util.integrations.Constants.PATCHES_PATH +import org.jf.dexlib2.builder.MutableMethodImplementation import org.jf.dexlib2.iface.Method import org.jf.dexlib2.util.MethodUtil import org.w3c.dom.Node +internal fun MutableMethodImplementation.injectHideCall( + index: Int, + register: Int, + patches: String, + method: String +) { + this.addInstruction( + index, + "invoke-static { v$register }, $PATCHES_PATH/$patches;->$method(Landroid/view/View;)V".toInstruction() + ) +} + +internal fun MutableMethodImplementation.injectTheme( + index: Int, + register: Int, + method: String +) { + this.addInstruction( + index, + "invoke-static { v$register }, $INTEGRATIONS_PATH/utils/ThemeHelper;->$method(I)V".toInstruction() + ) +} + // TODO: populate this to all patches /** * Convert a [MethodFingerprint] to a [PatchResultError]. @@ -41,4 +68,14 @@ fun MutableClass.transformMethods(transform: MutableMethod.() -> MutableMethod) internal fun Node.doRecursively(action: (Node) -> Unit) { action(this) for (i in 0 until this.childNodes.length) this.childNodes.item(i).doRecursively(action) -} \ No newline at end of file +} + +internal fun String.startsWithAny(vararg prefixes: String): Boolean { + for (prefix in prefixes) + if (this.startsWith(prefix)) + return true + + return false +} + + diff --git a/src/main/kotlin/app/revanced/shared/extensions/MethodExtensions.kt b/src/main/kotlin/app/revanced/shared/extensions/MethodExtensions.kt new file mode 100644 index 000000000..a664b7f66 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/extensions/MethodExtensions.kt @@ -0,0 +1,53 @@ +package app.revanced.shared.extensions + +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.PatchResultError +import app.revanced.patcher.util.proxy.mutableTypes.MutableClass +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import org.jf.dexlib2.builder.BuilderInstruction +import org.jf.dexlib2.builder.MutableMethodImplementation +import org.jf.dexlib2.iface.Method +import org.jf.dexlib2.iface.instruction.Instruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.FieldReference +import org.jf.dexlib2.iface.reference.MethodReference +import org.jf.dexlib2.iface.reference.Reference +import org.jf.dexlib2.immutable.reference.ImmutableMethodReference + +internal object MethodExtensions { + internal fun MutableMethodImplementation.insertBlocks( + startIndex: Int, + vararg blocks: List, + ) { + blocks.reversed().forEach { + this.addInstructions( + startIndex, it + ) + } + } + + internal fun MutableClass.addMethod(mutableMethod: MutableMethod) { + this.methods.add(mutableMethod) + } + + internal inline fun Instruction.toDescriptor(): String { + val reference = (this as ReferenceInstruction).reference + return when (T::class) { + MethodReference::class -> { + val methodReference = reference as MethodReference + "${methodReference.definingClass}->${methodReference.name}(${ + methodReference.parameterTypes.joinToString( + "" + ) { it } + })${methodReference.returnType}" + } + + FieldReference::class -> { + val fieldReference = reference as FieldReference + "${fieldReference.definingClass}->${fieldReference.name}:${fieldReference.type}" + } + + else -> throw PatchResultError("Unsupported reference type") + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/EmptyColorFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/EmptyColorFingerprint.kt new file mode 100644 index 000000000..fb74251eb --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/EmptyColorFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction +import org.jf.dexlib2.Opcode + +object EmptyColorFingerprint : MethodFingerprint( + "V", + opcodes = listOf(Opcode.DIV_LONG_2ADDR), + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { instruction -> + instruction.opcode.ordinal == Opcode.CONST.ordinal && + (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.emptycolorLabelId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/LegacyVideoAdsFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/LegacyVideoAdsFingerprint.kt new file mode 100644 index 000000000..9f1991e98 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/LegacyVideoAdsFingerprint.kt @@ -0,0 +1,25 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction + +object LegacyVideoAdsFingerprint : MethodFingerprint( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( + Opcode.CONST_WIDE_16, + Opcode.IPUT_WIDE, + Opcode.CONST_WIDE_16, + Opcode.IPUT_WIDE, + Opcode.IPUT_WIDE, + Opcode.IPUT_WIDE, + Opcode.IPUT_WIDE, + Opcode.CONST_4, + ), + customFingerprint = { methodDef -> + methodDef.implementation!!.instructions.any { + ((it as? NarrowLiteralInstruction)?.narrowLiteral == 4) + } + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/LithoThemeFingerprint.kt similarity index 91% rename from src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt rename to src/main/kotlin/app/revanced/shared/fingerprints/LithoThemeFingerprint.kt index ba6e29cf5..34c94e153 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/fingerprints/LithoThemeFingerprint.kt +++ b/src/main/kotlin/app/revanced/shared/fingerprints/LithoThemeFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.theme.fingerprints +package app.revanced.shared.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/MainstreamVideoAdsFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/MainstreamVideoAdsFingerprint.kt new file mode 100644 index 000000000..d822449a2 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/MainstreamVideoAdsFingerprint.kt @@ -0,0 +1,17 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object MainstreamVideoAdsFingerprint : MethodFingerprint( + "V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("L","Z"), listOf( + Opcode.IGET_OBJECT, + Opcode.INVOKE_VIRTUAL, + Opcode.MOVE_RESULT_OBJECT, + Opcode.CONST_4, + Opcode.IPUT_BOOLEAN, + Opcode.IF_NEZ + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/MainstreamVideoAdsParentFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/MainstreamVideoAdsParentFingerprint.kt new file mode 100644 index 000000000..c7af865d1 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/MainstreamVideoAdsParentFingerprint.kt @@ -0,0 +1,7 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint + +object MainstreamVideoAdsParentFingerprint : MethodFingerprint( + strings = listOf("exitSlot") +) diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/OnDrawFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/OnDrawFingerprint.kt new file mode 100644 index 000000000..bd16a7fa6 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/OnDrawFingerprint.kt @@ -0,0 +1,14 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags +import org.jf.dexlib2.Opcode + +object OnDrawFingerprint : MethodFingerprint ( + "V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), + listOf(Opcode.MOVE_OBJECT_FROM16, Opcode.MOVE_OBJECT_FROM16), + customFingerprint = { methodDef -> + methodDef.name == "onDraw" + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/PivotBarFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/PivotBarFingerprint.kt new file mode 100644 index 000000000..ba72f9959 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/PivotBarFingerprint.kt @@ -0,0 +1,16 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.WideLiteralInstruction + +object PivotBarFingerprint : MethodFingerprint( + customFingerprint = { methodDef -> + methodDef.implementation?.instructions?.any { + it.opcode.ordinal == Opcode.CONST.ordinal && + (it as WideLiteralInstruction).wideLiteral == SharedResourcdIdPatch.imageOnlyTabId + } == true + } +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/SubtitleButtonControllerFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/SubtitleButtonControllerFingerprint.kt similarity index 88% rename from src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/SubtitleButtonControllerFingerprint.kt rename to src/main/kotlin/app/revanced/shared/fingerprints/SubtitleButtonControllerFingerprint.kt index d42965f73..159f23907 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/autocaptions/fingerprints/SubtitleButtonControllerFingerprint.kt +++ b/src/main/kotlin/app/revanced/shared/fingerprints/SubtitleButtonControllerFingerprint.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.youtube.layout.autocaptions.fingerprints +package app.revanced.shared.fingerprints import app.revanced.patcher.extensions.or import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint diff --git a/src/main/kotlin/app/revanced/shared/fingerprints/TimebarFingerprint.kt b/src/main/kotlin/app/revanced/shared/fingerprints/TimebarFingerprint.kt new file mode 100644 index 000000000..989d6dc1a --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/fingerprints/TimebarFingerprint.kt @@ -0,0 +1,15 @@ +package app.revanced.shared.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import org.jf.dexlib2.AccessFlags + +object TimebarFingerprint : MethodFingerprint( + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + listOf("L"), + customFingerprint = { methodDef -> + methodDef.definingClass.endsWith("/TimeBar;") + && methodDef.name.contains("draw") + } +) diff --git a/src/main/kotlin/app/revanced/patches/all/interaction/gestures/patch/PredictiveBackGesturePatch.kt b/src/main/kotlin/app/revanced/shared/patches/gestures/PredictiveBackGesturePatch.kt similarity index 90% rename from src/main/kotlin/app/revanced/patches/all/interaction/gestures/patch/PredictiveBackGesturePatch.kt rename to src/main/kotlin/app/revanced/shared/patches/gestures/PredictiveBackGesturePatch.kt index 05beb7bd5..dc91faed0 100644 --- a/src/main/kotlin/app/revanced/patches/all/interaction/gestures/patch/PredictiveBackGesturePatch.kt +++ b/src/main/kotlin/app/revanced/shared/patches/gestures/PredictiveBackGesturePatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.all.interaction.gestures.patch +package app.revanced.shared.patches.gestures import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -9,7 +9,6 @@ import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.annotations.Patch -@Patch(false) @Name("predictive-back-gesture") @Description("Enables the predictive back gesture introduced on Android 13.") @Version("0.0.1") @@ -22,7 +21,7 @@ class PredictiveBackGesturePatch : ResourcePatch { if (attributes.getNamedItem(FLAG) != null) return@with document.createAttribute(FLAG) - .apply { value = "true" } + .apply { value = "false" } .let(attributes::setNamedItem) } @@ -34,4 +33,4 @@ class PredictiveBackGesturePatch : ResourcePatch { private companion object { const val FLAG = "android:enableOnBackInvokedCallback" } -} +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt b/src/main/kotlin/app/revanced/shared/patches/integrations/AbstractIntegrationsPatch.kt similarity index 97% rename from src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt rename to src/main/kotlin/app/revanced/shared/patches/integrations/AbstractIntegrationsPatch.kt index 2ef2e48dc..ff0708ba1 100644 --- a/src/main/kotlin/app/revanced/patches/shared/integrations/patch/AbstractIntegrationsPatch.kt +++ b/src/main/kotlin/app/revanced/shared/patches/integrations/AbstractIntegrationsPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.integrations.patch +package app.revanced.shared.patches.integrations import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Version @@ -38,7 +38,6 @@ abstract class AbstractIntegrationsPatch( "$integrationsDescriptor->context:Landroid/content/Context;" ) } ?: return PatchResultError("Could not find hook target fingerprint.") - return PatchResultSuccess() } diff --git a/src/main/kotlin/app/revanced/patches/shared/mapping/misc/patch/ResourceMappingPatch.kt b/src/main/kotlin/app/revanced/shared/patches/mapping/ResourceMappingPatch.kt similarity index 98% rename from src/main/kotlin/app/revanced/patches/shared/mapping/misc/patch/ResourceMappingPatch.kt rename to src/main/kotlin/app/revanced/shared/patches/mapping/ResourceMappingPatch.kt index b607dc283..f76ba4753 100644 --- a/src/main/kotlin/app/revanced/patches/shared/mapping/misc/patch/ResourceMappingPatch.kt +++ b/src/main/kotlin/app/revanced/shared/patches/mapping/ResourceMappingPatch.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.shared.mapping.misc.patch +package app.revanced.shared.patches.mapping import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name @@ -7,11 +7,10 @@ import app.revanced.patcher.data.ResourceContext import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.ResourcePatch -import org.w3c.dom.Element import java.util.* import java.util.concurrent.Executors import java.util.concurrent.TimeUnit - +import org.w3c.dom.Element @Name("resource-mapping") @Description("Creates a map of public resources.") diff --git a/src/main/kotlin/app/revanced/shared/patches/options/PatchOptions.kt b/src/main/kotlin/app/revanced/shared/patches/options/PatchOptions.kt new file mode 100644 index 000000000..4a46f2d94 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/patches/options/PatchOptions.kt @@ -0,0 +1,104 @@ +package app.revanced.shared.patches.options + +import app.revanced.patcher.annotation.Description +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.annotations.Patch +import app.revanced.patcher.patch.* + +@Patch +@Name("patch-options") +@Description("Create an options.toml file.") +@Version("0.0.1") +class PatchOptions : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + return PatchResultSuccess() + } + + /* + * Custom Branding Name + */ + + companion object : OptionsContainer() { + + /* + * Custom Branding Name + */ + internal var YouTube_AppName: String? by option( + PatchOption.StringOption( + key = "YouTube_AppName", + default = "ReVanced Extended", + title = "Application Name of YouTube", + description = "The name of the YouTube it will show on your home screen.", + required = true + ) + ) + + /* + * Custom Package Name (YouTube) + */ + internal var YouTube_PackageName: String? by option( + PatchOption.StringOption( + key = "YouTube_PackageName", + default = "app.rvx.android.youtube", + title = "Package Name of YouTube", + description = "The package name of the YouTube. (NON-ROOT user only)", + required = true + ) + ) + + /* + * Custom Package Name (YouTube Music) + */ + internal var Music_PackageName: String? by option( + PatchOption.StringOption( + key = "Music_PackageName", + default = "app.rvx.android.apps.youtube.music", + title = "Package Name of YouTube Music", + description = "The package name of the YouTube Music. (NON-ROOT user only)", + required = true + ) + ) + + /* + * Custom Speed Values + */ + internal var CustomSpeedArrays: String? by option( + PatchOption.StringOption( + key = "Custom_Speed_Arrays", + default = "0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 3.0, 5.0", + title = "Custom Speed Values", + description = "A list of custom video speeds. Be sure to separate them with commas (,).", + required = true + ) + ) + + /* + * Overlay Buttons Icon + */ + internal var Overlay_Buttons_Icon: String? by option( + PatchOption.StringOption( + key = "Overlay_Buttons_Icon", + default = "new", + title = "Overlay button icon selection", + description = "Choose an overlay buttons icon (old/new)", + required = true + ) + ) + + /* + * Theme + */ + internal var darkThemeBackgroundColor: String? by option( + PatchOption.StringOption( + key = "darkThemeBackgroundColor", + default = "@android:color/black", + title = "Background color for the dark theme", + description = "The background color of the dark theme. Can be a hex color or a resource reference.", + required = true + ) + ) + + } +} diff --git a/src/main/kotlin/app/revanced/shared/patches/settings/AbstractSettingsResourcePatch.kt b/src/main/kotlin/app/revanced/shared/patches/settings/AbstractSettingsResourcePatch.kt new file mode 100644 index 000000000..8fb07777b --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/patches/settings/AbstractSettingsResourcePatch.kt @@ -0,0 +1,49 @@ +package app.revanced.shared.patches.settings + +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import app.revanced.shared.util.resources.ResourceHelper +import app.revanced.shared.util.resources.ResourceUtils +import app.revanced.shared.util.resources.ResourceUtils.copyResources +import app.revanced.shared.util.resources.ResourceUtils.copyXmlNode +import org.w3c.dom.Element + +/** + * Abstract settings resource patch + * + * @param sourceDirectory Source directory to copy the preference template from + * @param sourcehostDirectory Source directory to copy the preference template from + */ +abstract class AbstractSettingsResourcePatch( + private val sourceDirectory: String, + private val sourcehostDirectory: String, + private val isYouTube: Boolean, +) : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + /* + * used for self-restart + */ + context.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") + }) + } + } + + /* + * Copy strings + */ + context.copyXmlNode(sourcehostDirectory, "values/strings.xml", "resources") + + /* initialize ReVanced Settings */ + if (isYouTube == true) { + context.copyResources(sourceDirectory, ResourceUtils.ResourceGroup("xml", "revanced_prefs.xml")) + ResourceHelper.initReVancedSettings(context) + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/LithoThemePatch.kt b/src/main/kotlin/app/revanced/shared/patches/theme/bytecode/GeneralThemePatch.kt similarity index 57% rename from src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/LithoThemePatch.kt rename to src/main/kotlin/app/revanced/shared/patches/theme/bytecode/GeneralThemePatch.kt index 6575ff4ec..906bcbbce 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/theme/patch/LithoThemePatch.kt +++ b/src/main/kotlin/app/revanced/shared/patches/theme/bytecode/GeneralThemePatch.kt @@ -1,21 +1,23 @@ -package app.revanced.patches.youtube.layout.theme.patch +package app.revanced.shared.patches.theme.bytecode -import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResultSuccess -import app.revanced.patches.youtube.layout.theme.annotations.ThemeCompatibility -import app.revanced.patches.youtube.layout.theme.fingerprints.LithoThemeFingerprint +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.fingerprints.LithoThemeFingerprint +import app.revanced.shared.patches.theme.resource.GeneralThemeResourcePatch +import app.revanced.shared.util.integrations.Constants.UTILS_PATH -@Name("litho-components-theme") -@Description("Applies a custom theme to litho components.") -@ThemeCompatibility +@Name("general-theme") +@DependsOn([GeneralThemeResourcePatch::class]) +@YouTubeCompatibility @Version("0.0.1") -class LithoThemePatch : BytecodePatch( +class GeneralThemePatch : BytecodePatch( listOf( LithoThemeFingerprint ) @@ -27,7 +29,7 @@ class LithoThemePatch : BytecodePatch( method.addInstructions( patchIndex, """ - invoke-static {p1}, Lapp/revanced/integrations/patches/LithoThemePatch;->applyLithoTheme(I)I + invoke-static {p1}, $UTILS_PATH/LithoThemePatch;->applyLithoTheme(I)I move-result p1 """ ) diff --git a/src/main/kotlin/app/revanced/shared/patches/theme/resource/GeneralThemeResourcePatch.kt b/src/main/kotlin/app/revanced/shared/patches/theme/resource/GeneralThemeResourcePatch.kt new file mode 100644 index 000000000..aea2ab768 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/patches/theme/resource/GeneralThemeResourcePatch.kt @@ -0,0 +1,85 @@ +package app.revanced.shared.patches.theme.resource + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.ResourceContext +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.ResourcePatch +import org.w3c.dom.Element + +@Name("general-theme-resource-patch") +@Version("0.0.1") +class GeneralThemeResourcePatch : ResourcePatch { + override fun execute(context: ResourceContext): PatchResult { + + // copies the resource file to change the splash screen color + context.xmlEditor["res/values/attrs.xml"].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + val newElement: Element = createElement("attr") + newElement.setAttribute("format", "reference") + newElement.setAttribute("name", "splashScreenColor") + + resourcesNode.appendChild(newElement) + } + } + + context.xmlEditor["res/values/styles.xml"].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + val newElement: Element = createElement("item") + newElement.setAttribute("name", "splashScreenColor") + + when (node.getAttribute("name")) { + "Base.Theme.YouTube.Launcher.Dark" -> { + newElement.appendChild(createTextNode("@color/yt_black1")) + + node.appendChild(newElement) + } + "Base.Theme.YouTube.Launcher.Light" -> { + newElement.appendChild(createTextNode("@color/yt_white1")); + + node.appendChild(newElement) + } + } + } + } + } + + context.xmlEditor["res/values-v31/styles.xml"].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + val newElement: Element = createElement("item") + newElement.setAttribute("name", "android:windowSplashScreenBackground") + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + if (node.getAttribute("name") == "Base.Theme.YouTube.Launcher") { + newElement.appendChild(createTextNode("?attr/splashScreenColor")) + + node.appendChild(newElement) + } + } + } + } + + arrayOf("drawable", "drawable-sw600dp").forEach { drawablePath -> + context.xmlEditor["res/$drawablePath/quantum_launchscreen_youtube.xml"].use { editor -> + val resourcesNode = editor.file.getElementsByTagName("item").item(0) as Element + + if (resourcesNode.attributes.getNamedItem("android:drawable") != null) + resourcesNode.setAttribute("android:drawable", "?attr/splashScreenColor") + } + } + + return PatchResultSuccess() + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/patches/timebar/HookTimebarPatch.kt b/src/main/kotlin/app/revanced/shared/patches/timebar/HookTimebarPatch.kt new file mode 100644 index 000000000..9ab891c8e --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/patches/timebar/HookTimebarPatch.kt @@ -0,0 +1,47 @@ +package app.revanced.shared.patches.timebar + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult +import app.revanced.patcher.patch.annotations.DependsOn +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch +import app.revanced.shared.annotation.YouTubeCompatibility +import app.revanced.shared.fingerprints.EmptyColorFingerprint +import app.revanced.shared.fingerprints.OnDrawFingerprint +import app.revanced.shared.fingerprints.TimebarFingerprint +import app.revanced.shared.extensions.toErrorResult + +@Name("hook-timebar-patch") +@DependsOn([SharedResourcdIdPatch::class]) +@YouTubeCompatibility +@Version("0.0.1") +class HookTimebarPatch : BytecodePatch( + listOf( + EmptyColorFingerprint, + TimebarFingerprint + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + EmptyColorFingerprintResult = EmptyColorFingerprint.result ?: return EmptyColorFingerprint.toErrorResult() + + OnDrawFingerprint.resolve(context, EmptyColorFingerprintResult.classDef) + SetTimbarFingerprintResult = OnDrawFingerprint.result ?: return OnDrawFingerprint.toErrorResult() + + TimbarFingerprintResult = TimebarFingerprint.result ?: return TimebarFingerprint.toErrorResult() + + return PatchResultSuccess() + } + + internal companion object { + lateinit var EmptyColorFingerprintResult: MethodFingerprintResult + lateinit var SetTimbarFingerprintResult: MethodFingerprintResult + lateinit var TimbarFingerprintResult: MethodFingerprintResult + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/patches/videoads/GeneralVideoAdsPatch.kt b/src/main/kotlin/app/revanced/shared/patches/videoads/GeneralVideoAdsPatch.kt new file mode 100644 index 000000000..7ddff6390 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/patches/videoads/GeneralVideoAdsPatch.kt @@ -0,0 +1,78 @@ +package app.revanced.shared.patches.videoads + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.data.toMethodWalker +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.instruction +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.PatchResult +import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.util.smali.ExternalLabel +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod +import app.revanced.shared.fingerprints.LegacyVideoAdsFingerprint +import app.revanced.shared.fingerprints.MainstreamVideoAdsFingerprint +import app.revanced.shared.fingerprints.MainstreamVideoAdsParentFingerprint +import app.revanced.shared.extensions.toErrorResult + +@Name("general-video-ads-patch") +@Version("0.0.1") +class GeneralVideoAdsPatch : BytecodePatch( + listOf( + LegacyVideoAdsFingerprint, + MainstreamVideoAdsParentFingerprint, + ) +) { + override fun execute(context: BytecodeContext): PatchResult { + val LegacyVideoAdsResult = LegacyVideoAdsFingerprint.result ?: return LegacyVideoAdsFingerprint.toErrorResult() + + LegacyVideoAdsMethod = + context.toMethodWalker(LegacyVideoAdsResult.method) + .nextMethod(13, true) + .getMethod() as MutableMethod + + MainstreamVideoAdsFingerprint.resolve(context, MainstreamVideoAdsParentFingerprint.result!!.classDef) + + val MainstreamAdsResult = MainstreamVideoAdsFingerprint.result ?: return MainstreamVideoAdsFingerprint.toErrorResult() + + MainstreamVideoAdsMethod = MainstreamAdsResult.mutableMethod + + InsertIndex = MainstreamAdsResult.scanResult.patternScanResult!!.endIndex + + return PatchResultSuccess() + } + + internal companion object { + var InsertIndex: Int = 0 + + lateinit var LegacyVideoAdsMethod: MutableMethod + lateinit var MainstreamVideoAdsMethod: MutableMethod + + fun injectLegacyAds( + descriptor: String + ) { + LegacyVideoAdsMethod.addInstructions( + 0, """ + invoke-static {}, $descriptor + move-result v1 + """ + ) + } + + fun injectMainstreamAds( + descriptor: String + ) { + MainstreamVideoAdsMethod.addInstructions( + InsertIndex, """ + invoke-static {}, $descriptor + move-result v1 + if-nez v1, :show_video_ads + return-void + """, listOf(ExternalLabel("show_video_ads", MainstreamVideoAdsMethod.instruction(InsertIndex))) + ) + } + + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt b/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt new file mode 100644 index 000000000..b79fdde6b --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/util/bytecode/BytecodeHelper.kt @@ -0,0 +1,75 @@ +package app.revanced.shared.util.bytecode + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.addInstruction +import app.revanced.patcher.extensions.replaceInstruction +import app.revanced.shared.util.integrations.Constants.UTILS_PATH +import org.jf.dexlib2.Opcode + +internal object BytecodeHelper { + + fun injectInit( + context: BytecodeContext, + descriptor: String, + methods: String + ) { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + if (classDef.type.endsWith("WatchWhileActivity;") && method.name == "onCreate") { + val hookMethod = + context.proxy(classDef).mutableClass.methods.first { it.name == "onCreate" } + + hookMethod.addInstruction( + 2, + "invoke-static {}, $UTILS_PATH/$descriptor;->$methods()V" + ) + } + } + } + } + + fun injectBackPressed( + context: BytecodeContext + ) { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + if (classDef.type.endsWith("WatchWhileActivity;") && method.name == "onBackPressed") { + val onBackPressedMethod = + context.proxy(classDef).mutableClass.methods.first { it.name == "onBackPressed" } + + val onBackPressedMethodInstructions = + onBackPressedMethod.implementation!!.instructions + + for ((index, instruction) in onBackPressedMethodInstructions.withIndex()) { + if (instruction.opcode != Opcode.RETURN_VOID) continue + + onBackPressedMethod.addInstruction( + index, + "invoke-static {p0}, $UTILS_PATH/DoubleBackToExitPatch;->doubleBackToExit(Lcom/google/android/apps/youtube/app/watchwhile/WatchWhileActivity;)V" + ) + break + } + } + } + } + } + + fun patchStatus( + context: BytecodeContext, + name: String + ) { + context.classes.forEach { classDef -> + classDef.methods.forEach { method -> + if (classDef.type.endsWith("PatchStatus;") && method.name == "$name") { + val patchStatusMethod = + context.proxy(classDef).mutableClass.methods.first { it.name == "$name" } + + patchStatusMethod.replaceInstruction( + 0, + "const/4 v0, 0x1" + ) + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/util/integrations/Constants.kt b/src/main/kotlin/app/revanced/shared/util/integrations/Constants.kt new file mode 100644 index 000000000..3da4a91f8 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/util/integrations/Constants.kt @@ -0,0 +1,20 @@ +package app.revanced.shared.util.integrations + +internal object Constants { + const val INTEGRATIONS_PATH = "Lapp/revanced/integrations" + const val PATCHES_PATH = "$INTEGRATIONS_PATH/patches" + + const val ADS_PATH = "$PATCHES_PATH/ads" + const val BUTTON_PATH = "$PATCHES_PATH/button" + + const val GENERAL_LAYOUT = "$PATCHES_PATH/layout/GeneralLayoutPatch;" + const val PLAYER_LAYOUT = "$PATCHES_PATH/layout/PlayerLayoutPatch;" + const val FULLSCREEN_LAYOUT = "$PATCHES_PATH/layout/FullscreenLayoutPatch;" + const val FLYOUTPANEL_LAYOUT = "$PATCHES_PATH/layout/FlyoutPanelLayoutPatch;" + const val SEEKBAR_LAYOUT = "$PATCHES_PATH/layout/SeekbarLayoutPatch;" + + const val EXTENDED_PATH = "$PATCHES_PATH/extended" + const val MISC_PATH = "$PATCHES_PATH/misc" + const val VIDEO_PATH = "$PATCHES_PATH/video" + const val UTILS_PATH = "$PATCHES_PATH/utils" +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/microg/Constants.kt b/src/main/kotlin/app/revanced/shared/util/microg/Constants.kt similarity index 99% rename from src/main/kotlin/app/revanced/util/microg/Constants.kt rename to src/main/kotlin/app/revanced/shared/util/microg/Constants.kt index 912b97561..c1087db09 100644 --- a/src/main/kotlin/app/revanced/util/microg/Constants.kt +++ b/src/main/kotlin/app/revanced/shared/util/microg/Constants.kt @@ -1,4 +1,4 @@ -package app.revanced.util.microg +package app.revanced.shared.util.microg /** * constants for microG builds with signature spoofing diff --git a/src/main/kotlin/app/revanced/util/microg/MicroGBytecodeHelper.kt b/src/main/kotlin/app/revanced/shared/util/microg/MicroGBytecodeHelper.kt similarity index 97% rename from src/main/kotlin/app/revanced/util/microg/MicroGBytecodeHelper.kt rename to src/main/kotlin/app/revanced/shared/util/microg/MicroGBytecodeHelper.kt index b4b4038cb..40e662c0a 100644 --- a/src/main/kotlin/app/revanced/util/microg/MicroGBytecodeHelper.kt +++ b/src/main/kotlin/app/revanced/shared/util/microg/MicroGBytecodeHelper.kt @@ -1,4 +1,4 @@ -package app.revanced.util.microg +package app.revanced.shared.util.microg import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.extensions.addInstruction @@ -7,10 +7,10 @@ import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.util.proxy.mutableTypes.MutableClass import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.util.microg.Constants.ACTIONS -import app.revanced.util.microg.Constants.AUTHORITIES -import app.revanced.util.microg.Constants.MICROG_VENDOR -import app.revanced.util.microg.Constants.PERMISSIONS +import app.revanced.shared.util.microg.Constants.ACTIONS +import app.revanced.shared.util.microg.Constants.AUTHORITIES +import app.revanced.shared.util.microg.Constants.MICROG_VENDOR +import app.revanced.shared.util.microg.Constants.PERMISSIONS import org.jf.dexlib2.Opcode import org.jf.dexlib2.builder.instruction.BuilderInstruction21c import org.jf.dexlib2.iface.instruction.formats.Instruction21c diff --git a/src/main/kotlin/app/revanced/util/microg/MicroGManifestHelper.kt b/src/main/kotlin/app/revanced/shared/util/microg/MicroGManifestHelper.kt similarity index 85% rename from src/main/kotlin/app/revanced/util/microg/MicroGManifestHelper.kt rename to src/main/kotlin/app/revanced/shared/util/microg/MicroGManifestHelper.kt index 003fa00e3..2cef816ac 100644 --- a/src/main/kotlin/app/revanced/util/microg/MicroGManifestHelper.kt +++ b/src/main/kotlin/app/revanced/shared/util/microg/MicroGManifestHelper.kt @@ -1,10 +1,10 @@ -package app.revanced.util.microg +package app.revanced.shared.util.microg import app.revanced.patcher.data.ResourceContext -import app.revanced.util.microg.Constants.META_GMS_PACKAGE_NAME -import app.revanced.util.microg.Constants.META_SPOOFED_PACKAGE_NAME -import app.revanced.util.microg.Constants.META_SPOOFED_PACKAGE_SIGNATURE -import app.revanced.util.microg.Constants.MICROG_VENDOR +import app.revanced.shared.util.microg.Constants.META_GMS_PACKAGE_NAME +import app.revanced.shared.util.microg.Constants.META_SPOOFED_PACKAGE_NAME +import app.revanced.shared.util.microg.Constants.META_SPOOFED_PACKAGE_SIGNATURE +import app.revanced.shared.util.microg.Constants.MICROG_VENDOR import org.w3c.dom.Element import org.w3c.dom.Node diff --git a/src/main/kotlin/app/revanced/util/microg/MicroGResourceHelper.kt b/src/main/kotlin/app/revanced/shared/util/microg/MicroGResourceHelper.kt similarity index 60% rename from src/main/kotlin/app/revanced/util/microg/MicroGResourceHelper.kt rename to src/main/kotlin/app/revanced/shared/util/microg/MicroGResourceHelper.kt index 348e1458f..b37f34484 100644 --- a/src/main/kotlin/app/revanced/util/microg/MicroGResourceHelper.kt +++ b/src/main/kotlin/app/revanced/shared/util/microg/MicroGResourceHelper.kt @@ -1,46 +1,29 @@ -package app.revanced.util.microg +package app.revanced.shared.util.microg import app.revanced.patcher.data.ResourceContext -import app.revanced.util.resources.ResourceUtils.mergeStrings /** * Helper class for applying resource patches needed for the microg-support patches. */ internal object MicroGResourceHelper { - - /** - * Add necessary strings to the strings.xml file. - * - * @param context The resource context. - * @param stringsHost The file which hosts the strings. - */ - fun addStrings(context: ResourceContext, stringsHost: String = "microg/host/values/strings.xml") = context.mergeStrings(stringsHost) - /** * Patch the manifest to work with MicroG. * - * @param context The resource context. - * @param fromPackageName The original package name. + * @param context Bytecode context. + * @param fromPackageName Original package name. * @param toPackageName The package name to accept. * @param toName The new name of the app. */ fun patchManifest( context: ResourceContext, fromPackageName: String, - toPackageName: String, - toName: String + toPackageName: String ) { val manifest = context["AndroidManifest.xml"].readText() context["AndroidManifest.xml"].writeText( manifest.replace( "package=\"$fromPackageName", "package=\"$toPackageName" - ).replace( - "android:label=\"@string/app_name", - "android:label=\"$toName" - ).replace( - "android:label=\"@string/app_launcher_name", - "android:label=\"$toName" ).replace( "android:authorities=\"$fromPackageName", "android:authorities=\"$toPackageName" diff --git a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/utils/InjectionUtils.kt b/src/main/kotlin/app/revanced/shared/util/pivotbar/InjectionUtils.kt similarity index 95% rename from src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/utils/InjectionUtils.kt rename to src/main/kotlin/app/revanced/shared/util/pivotbar/InjectionUtils.kt index 8667b10d0..da5155561 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/layout/pivotbar/utils/InjectionUtils.kt +++ b/src/main/kotlin/app/revanced/shared/util/pivotbar/InjectionUtils.kt @@ -1,10 +1,10 @@ -package app.revanced.patches.youtube.layout.pivotbar.utils +package app.revanced.shared.util.pivotbar import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.instruction import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import org.jf.dexlib2.Opcode.MOVE_RESULT_OBJECT import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.Opcode.MOVE_RESULT_OBJECT internal object InjectionUtils { const val REGISTER_TEMPLATE_REPLACEMENT: String = "REGISTER_INDEX" diff --git a/src/main/kotlin/app/revanced/shared/util/resources/IconHelper.kt b/src/main/kotlin/app/revanced/shared/util/resources/IconHelper.kt new file mode 100644 index 000000000..069bff888 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/util/resources/IconHelper.kt @@ -0,0 +1,82 @@ +package app.revanced.shared.util.resources + +import app.revanced.patcher.data.ResourceContext +import java.nio.file.Files +import java.nio.file.StandardCopyOption +import org.w3c.dom.Element + +internal object IconHelper { + + fun customIcon( + context: ResourceContext, + iconName: String + ) { + val classLoader = this.javaClass.classLoader + val resDirectory = context["res"] + + val Appnames = arrayOf( + "adaptiveproduct_youtube_background_color_108", + "adaptiveproduct_youtube_foreground_color_108", + "ic_launcher", + "ic_launcher_round" + ) + + val Splashnames = arrayOf( + "product_logo_youtube_color_24", + "product_logo_youtube_color_36", + "product_logo_youtube_color_144", + "product_logo_youtube_color_192" + ) + + mapOf( + "xxxhdpi" to 192, + "xxhdpi" to 144, + "xhdpi" to 96, + "hdpi" to 72, + "mdpi" to 48 + ).forEach { (iconDirectory, size) -> + Appnames.forEach iconLoop@{ name -> + Files.copy( + classLoader.getResourceAsStream("youtube/branding/$iconName/launchericon/$size/$name.png")!!, + resDirectory.resolve("mipmap-$iconDirectory").resolve("$name.png").toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + Splashnames.forEach iconLoop@{ name -> + Files.copy( + classLoader.getResourceAsStream("youtube/branding/$iconName/splashicon/$size/$name.png")!!, + resDirectory.resolve("drawable-$iconDirectory").resolve("$name.png").toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + + context.xmlEditor["res/values-v31/styles.xml"].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + if (node.getAttribute("name") == "Base.Theme.YouTube.Launcher") { + node.removeChild(node.childNodes.item(0)) + } + } + } + } + + try { + arrayOf("drawable" to arrayOf("adaptive_monochrome_ic_youtube_launcher")).forEach { (path, resourceNames) -> + resourceNames.forEach { name -> + val relativePath = "$path/$name.xml" + + Files.copy( + classLoader.getResourceAsStream("youtube/branding/$iconName/monochromeicon/$relativePath")!!, + context["res"].resolve(relativePath).toPath(), + StandardCopyOption.REPLACE_EXISTING + ) + } + } + } catch (e: Exception) {} + } +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/shared/util/resources/ResourceHelper.kt b/src/main/kotlin/app/revanced/shared/util/resources/ResourceHelper.kt new file mode 100644 index 000000000..8827a44e0 --- /dev/null +++ b/src/main/kotlin/app/revanced/shared/util/resources/ResourceHelper.kt @@ -0,0 +1,269 @@ +package app.revanced.shared.util.resources + +import app.revanced.patcher.data.ResourceContext +import org.w3c.dom.Element + +internal object ResourceHelper { + + fun addEntryValues( + context: ResourceContext, + speed: String + ) { + var path = "res/values/arrays.xml" + + context.xmlEditor[path].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + val newElement: Element = createElement("item") + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + if (node.getAttribute("name") == "revanced_video_speed_entry_values") { + newElement.appendChild(createTextNode("$speed")) + + node.appendChild(newElement) + } + } + } + } + } + + fun addEntries( + context: ResourceContext, + speed: String + ) { + var path = "res/values/arrays.xml" + + context.xmlEditor[path].use { editor -> + with(editor.file) { + val resourcesNode = getElementsByTagName("resources").item(0) as Element + + val newElement: Element = createElement("item") + + for (i in 0 until resourcesNode.childNodes.length) { + val node = resourcesNode.childNodes.item(i) as? Element ?: continue + + if (node.getAttribute("name") == "revanced_video_speed_entries") { + newElement.appendChild(createTextNode("$speed")) + + node.appendChild(newElement) + } + } + } + } + context[path].writeText( + context[path].readText().replace("1.0x", "@string/shorts_speed_control_normal_label") + ) + } + + fun addSettings( + context: ResourceContext, + PreferenceCategory: String, + Preference: String, + Settings: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText() + .replace("", "") + .replace("", "") + .replace("", "") + ) + } + + fun addSettings2( + context: ResourceContext, + PreferenceCategory: String, + Preference: String, + Settings: String, + Settings2: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText() + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + ) + } + + fun addSettings3( + context: ResourceContext, + PreferenceCategory: String, + Preference: String, + Settings: String, + Settings2: String, + Settings3: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText() + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + ) + } + + fun addSettings4( + context: ResourceContext, + PreferenceCategory: String, + Preference: String, + Settings: String, + Settings2: String, + Settings3: String, + Settings4: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText() + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + ) + } + + fun addSettings5( + context: ResourceContext, + PreferenceCategory: String, + Preference: String, + Settings: String, + Settings2: String, + Settings3: String, + Settings4: String, + Settings5: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText() + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", "") + ) + } + + fun initReVancedSettings( + context: ResourceContext + ) { + val fragment = context["res/xml/settings_fragment.xml"] + fragment.writeText( + fragment.readText().replace( + "DeveloperPrefsFragment\" app:iconSpaceReserved=\"false\" />", + "DeveloperPrefsFragment\" app:iconSpaceReserved=\"false\" />" + ) + ) + } + + fun addReVancedSettings( + context: ResourceContext, + Preference: String + ) { + val fragment = context["res/xml/settings_fragment.xml"] + fragment.writeText( + fragment.readText() + .replace("", "") + ) + } + + fun patchSuccess( + context: ResourceContext, + name: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText().replace( + "\"$name\" android:summary=\"@string/revanced_patches_excluded", + "\"$name\" android:summary=\"@string/revanced_patches_included" + ) + ) + } + + fun themePatchSuccess( + context: ResourceContext, + before: String, + after: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText().replace( + "@string/revanced_themes_$before", + "@string/revanced_themes_$after" + ) + ) + } + + fun iconPatchSuccess( + context: ResourceContext, + targeticon: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText() + .replace( + "@string/revanced_icons_blue", + "@string/revanced_icons_default" + ).replace( + "@string/revanced_icons_red", + "@string/revanced_icons_default" + ).replace( + "@string/revanced_icons_revancify", + "@string/revanced_icons_default" + ) + .replace( + "@string/revanced_icons_default", + "@string/revanced_icons_$targeticon" + ) + ) + } + + fun labelPatchSuccess( + context: ResourceContext, + appName: String + ) { + val prefs = context["res/xml/revanced_prefs.xml"] + prefs.writeText( + prefs.readText().replace( + "@string/revanced_labels_default", + "$appName" + ) + ) + } + +} \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt b/src/main/kotlin/app/revanced/shared/util/resources/ResourceUtils.kt similarity index 57% rename from src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt rename to src/main/kotlin/app/revanced/shared/util/resources/ResourceUtils.kt index be6a77486..229690cbc 100644 --- a/src/main/kotlin/app/revanced/util/resources/ResourceUtils.kt +++ b/src/main/kotlin/app/revanced/shared/util/resources/ResourceUtils.kt @@ -1,34 +1,11 @@ -package app.revanced.util.resources +package app.revanced.shared.util.resources import app.revanced.patcher.data.DomFileEditor import app.revanced.patcher.data.ResourceContext -import app.revanced.patches.shared.settings.preference.impl.StringResource -import app.revanced.patches.youtube.misc.settings.bytecode.patch.SettingsPatch -import org.w3c.dom.Node import java.nio.file.Files import java.nio.file.StandardCopyOption internal object ResourceUtils { - - /** - * Merge strings. This manages [StringResource]s automatically. - * @param host The hosting xml resource. Needs to be a valid strings.xml resource. - */ - internal fun ResourceContext.mergeStrings(host: String) { - this.iterateXmlNodeChildren(host, "resources") { - // TODO: figure out why this is needed - if (!it.hasAttributes()) return@iterateXmlNodeChildren - - val attributes = it.attributes - val key = attributes.getNamedItem("name")!!.nodeValue!! - val value = it.textContent!! - - val formatted = attributes.getNamedItem("formatted") == null - - SettingsPatch.addString(key, value, formatted) - } - } - /** * Copy resources from the current class loader to the resource directory. * @param sourceResourceDirectory The source resource directory name. @@ -57,21 +34,20 @@ internal object ResourceUtils { internal class ResourceGroup(val resourceDirectoryName: String, vararg val resources: String) /** - * Iterate through the children of a node by its tag. - * @param resource The xml resource. - * @param targetTag The target xml node. - * @param callback The callback to call when iterating over the nodes. + * Copy resources from the current class loader to the resource directory. + * @param resourceDirectory The directory of the resource. + * @param targetResource The target resource. + * @param elementTag The element to copy. */ - internal fun ResourceContext.iterateXmlNodeChildren( - resource: String, - targetTag: String, - callback: (node: Node) -> Unit - ) = - xmlEditor[ResourceUtils.javaClass.classLoader.getResourceAsStream(resource)!!].use { - val stringsNode = it.file.getElementsByTagName(targetTag).item(0).childNodes - for (i in 1 until stringsNode.length - 1) callback(stringsNode.item(i)) - } + internal fun ResourceContext.copyXmlNode(resourceDirectory: String, targetResource: String, elementTag: String) { + val stringsResourceInputStream = ResourceUtils.javaClass.classLoader.getResourceAsStream("$resourceDirectory/$targetResource")!! + // Copy nodes from the resources node to the real resource node + elementTag.copyXmlNode( + this.xmlEditor[stringsResourceInputStream], + this.xmlEditor["res/$targetResource"] + ).close() + } /** * Copies the specified node of the source [DomFileEditor] to the target [DomFileEditor]. @@ -79,7 +55,7 @@ internal object ResourceUtils { * @param target the target [DomFileEditor]- * @return AutoCloseable that closes the target [DomFileEditor]s. */ - fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable { + internal fun String.copyXmlNode(source: DomFileEditor, target: DomFileEditor): AutoCloseable { val hostNodes = source.file.getElementsByTagName(this).item(0).childNodes val destinationResourceFile = target.file diff --git a/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png deleted file mode 100644 index e2dc8a53f..000000000 Binary files a/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_background_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png deleted file mode 100644 index e5a73b561..000000000 Binary files a/src/main/resources/branding/mipmap-hdpi/adaptiveproduct_youtube_foreground_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-hdpi/ic_launcher.png b/src/main/resources/branding/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index dc967b770..000000000 Binary files a/src/main/resources/branding/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-hdpi/ic_launcher_round.png b/src/main/resources/branding/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index dc967b770..000000000 Binary files a/src/main/resources/branding/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png deleted file mode 100644 index 4dee1752a..000000000 Binary files a/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_background_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png deleted file mode 100644 index 3d26f5b2b..000000000 Binary files a/src/main/resources/branding/mipmap-mdpi/adaptiveproduct_youtube_foreground_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-mdpi/ic_launcher.png b/src/main/resources/branding/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 4e3735d01..000000000 Binary files a/src/main/resources/branding/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-mdpi/ic_launcher_round.png b/src/main/resources/branding/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index 4e3735d01..000000000 Binary files a/src/main/resources/branding/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png deleted file mode 100644 index 49d5f450c..000000000 Binary files a/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_background_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png deleted file mode 100644 index 4f66f60a3..000000000 Binary files a/src/main/resources/branding/mipmap-xhdpi/adaptiveproduct_youtube_foreground_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xhdpi/ic_launcher.png b/src/main/resources/branding/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 471c9779e..000000000 Binary files a/src/main/resources/branding/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xhdpi/ic_launcher_round.png b/src/main/resources/branding/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index 471c9779e..000000000 Binary files a/src/main/resources/branding/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png deleted file mode 100644 index 1a92bea23..000000000 Binary files a/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_background_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png deleted file mode 100644 index 777daea51..000000000 Binary files a/src/main/resources/branding/mipmap-xxhdpi/adaptiveproduct_youtube_foreground_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxhdpi/ic_launcher.png b/src/main/resources/branding/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 6e2178566..000000000 Binary files a/src/main/resources/branding/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxhdpi/ic_launcher_round.png b/src/main/resources/branding/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index 6e2178566..000000000 Binary files a/src/main/resources/branding/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png deleted file mode 100644 index 9c4462f86..000000000 Binary files a/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_background_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png deleted file mode 100644 index 0abe542a1..000000000 Binary files a/src/main/resources/branding/mipmap-xxxhdpi/adaptiveproduct_youtube_foreground_color_108.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher.png b/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index c0505bf87..000000000 Binary files a/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher_round.png b/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index c0505bf87..000000000 Binary files a/src/main/resources/branding/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/src/main/resources/downloads/drawable/revanced_yt_download_button.xml b/src/main/resources/downloads/drawable/revanced_yt_download_button.xml deleted file mode 100644 index 69ab6992b..000000000 --- a/src/main/resources/downloads/drawable/revanced_yt_download_button.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml b/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml deleted file mode 100644 index 23254785a..000000000 --- a/src/main/resources/downloads/host/layout/youtube_controls_bottom_ui_container.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/main/resources/downloads/host/values/strings.xml b/src/main/resources/downloads/host/values/strings.xml deleted file mode 100644 index 957d490fe..000000000 --- a/src/main/resources/downloads/host/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - is not installed. Please install it. - diff --git a/src/main/resources/microg/host/values/strings.xml b/src/main/resources/microg/host/values/strings.xml deleted file mode 100644 index c5c1f69bd..000000000 --- a/src/main/resources/microg/host/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - Vanced MicroG is not installed. Please install it. - diff --git a/src/main/resources/music/branding/red/launchericon/144/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/red/launchericon/144/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..913a2368c Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/144/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/144/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/red/launchericon/144/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..3d955e903 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/144/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/144/ic_launcher_release.png b/src/main/resources/music/branding/red/launchericon/144/ic_launcher_release.png new file mode 100644 index 000000000..5f127cb61 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/144/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/red/launchericon/192/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/red/launchericon/192/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..71d6873d5 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/192/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/192/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/red/launchericon/192/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..0fb4827df Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/192/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/192/ic_launcher_release.png b/src/main/resources/music/branding/red/launchericon/192/ic_launcher_release.png new file mode 100644 index 000000000..2d07e46b5 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/192/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/red/launchericon/48/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/red/launchericon/48/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..0470723cb Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/48/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/48/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/red/launchericon/48/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..4836e22f8 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/48/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/48/ic_launcher_release.png b/src/main/resources/music/branding/red/launchericon/48/ic_launcher_release.png new file mode 100644 index 000000000..7a5f9bcb8 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/48/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/red/launchericon/72/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/red/launchericon/72/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..ef099728a Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/72/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/72/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/red/launchericon/72/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..0add36364 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/72/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/72/ic_launcher_release.png b/src/main/resources/music/branding/red/launchericon/72/ic_launcher_release.png new file mode 100644 index 000000000..31f74279c Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/72/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/red/launchericon/96/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/red/launchericon/96/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..a55a6ed73 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/96/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/96/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/red/launchericon/96/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..8a8130206 Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/96/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/red/launchericon/96/ic_launcher_release.png b/src/main/resources/music/branding/red/launchericon/96/ic_launcher_release.png new file mode 100644 index 000000000..0a5873c8e Binary files /dev/null and b/src/main/resources/music/branding/red/launchericon/96/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-hdpi/action_bar_logo.png b/src/main/resources/music/branding/red/resource/drawable-hdpi/action_bar_logo.png new file mode 100644 index 000000000..4495a5b4b Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-hdpi/action_bar_logo.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-hdpi/action_bar_logo_release.png b/src/main/resources/music/branding/red/resource/drawable-hdpi/action_bar_logo_release.png new file mode 100644 index 000000000..95a027561 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-hdpi/action_bar_logo_release.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-hdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-hdpi/record.png new file mode 100644 index 000000000..583da2af1 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-hdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-large-hdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-large-hdpi/record.png new file mode 100644 index 000000000..ab1f650a4 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-large-hdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-large-mdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-large-mdpi/record.png new file mode 100644 index 000000000..90d99867b Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-large-mdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-large-xhdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-large-xhdpi/record.png new file mode 100644 index 000000000..e383a49c6 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-large-xhdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-mdpi/action_bar_logo.png b/src/main/resources/music/branding/red/resource/drawable-mdpi/action_bar_logo.png new file mode 100644 index 000000000..693e813b7 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-mdpi/action_bar_logo.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-mdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-mdpi/record.png new file mode 100644 index 000000000..c1ed1f590 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-mdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xhdpi/action_bar_logo.png b/src/main/resources/music/branding/red/resource/drawable-xhdpi/action_bar_logo.png new file mode 100644 index 000000000..22292f172 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xhdpi/action_bar_logo.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xhdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-xhdpi/record.png new file mode 100644 index 000000000..86758e114 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xhdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xlarge-hdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-xlarge-hdpi/record.png new file mode 100644 index 000000000..0fe969087 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xlarge-hdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xlarge-mdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-xlarge-mdpi/record.png new file mode 100644 index 000000000..86758e114 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xlarge-mdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xxhdpi/action_bar_logo.png b/src/main/resources/music/branding/red/resource/drawable-xxhdpi/action_bar_logo.png new file mode 100644 index 000000000..6c9118340 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xxhdpi/action_bar_logo.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xxhdpi/record.png b/src/main/resources/music/branding/red/resource/drawable-xxhdpi/record.png new file mode 100644 index 000000000..0fe969087 Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xxhdpi/record.png differ diff --git a/src/main/resources/music/branding/red/resource/drawable-xxxhdpi/action_bar_logo.png b/src/main/resources/music/branding/red/resource/drawable-xxxhdpi/action_bar_logo.png new file mode 100644 index 000000000..66d00c71f Binary files /dev/null and b/src/main/resources/music/branding/red/resource/drawable-xxxhdpi/action_bar_logo.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/144/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/revancify/launchericon/144/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..d19389745 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/144/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/144/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/revancify/launchericon/144/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..f9367d7ca Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/144/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/144/ic_launcher_release.png b/src/main/resources/music/branding/revancify/launchericon/144/ic_launcher_release.png new file mode 100644 index 000000000..30a317148 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/144/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/192/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/revancify/launchericon/192/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..1654ce557 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/192/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/192/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/revancify/launchericon/192/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..19defcfcb Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/192/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/192/ic_launcher_release.png b/src/main/resources/music/branding/revancify/launchericon/192/ic_launcher_release.png new file mode 100644 index 000000000..855ebd1e0 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/192/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/48/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/revancify/launchericon/48/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..79aa7a37a Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/48/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/48/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/revancify/launchericon/48/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..eb3881851 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/48/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/48/ic_launcher_release.png b/src/main/resources/music/branding/revancify/launchericon/48/ic_launcher_release.png new file mode 100644 index 000000000..4812d2da8 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/48/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/72/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/revancify/launchericon/72/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..b0f78e9dd Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/72/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/72/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/revancify/launchericon/72/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..d96cc3542 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/72/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/72/ic_launcher_release.png b/src/main/resources/music/branding/revancify/launchericon/72/ic_launcher_release.png new file mode 100644 index 000000000..395f45a42 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/72/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/96/adaptiveproduct_youtube_music_background_color_108.png b/src/main/resources/music/branding/revancify/launchericon/96/adaptiveproduct_youtube_music_background_color_108.png new file mode 100644 index 000000000..4b097e794 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/96/adaptiveproduct_youtube_music_background_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/96/adaptiveproduct_youtube_music_foreground_color_108.png b/src/main/resources/music/branding/revancify/launchericon/96/adaptiveproduct_youtube_music_foreground_color_108.png new file mode 100644 index 000000000..6510ca5e0 Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/96/adaptiveproduct_youtube_music_foreground_color_108.png differ diff --git a/src/main/resources/music/branding/revancify/launchericon/96/ic_launcher_release.png b/src/main/resources/music/branding/revancify/launchericon/96/ic_launcher_release.png new file mode 100644 index 000000000..e4a1f4f1f Binary files /dev/null and b/src/main/resources/music/branding/revancify/launchericon/96/ic_launcher_release.png differ diff --git a/src/main/resources/music/branding/revancify/monochromeicon/drawable/ic_app_icons_themed_youtube_music.xml b/src/main/resources/music/branding/revancify/monochromeicon/drawable/ic_app_icons_themed_youtube_music.xml new file mode 100644 index 000000000..469a9378d --- /dev/null +++ b/src/main/resources/music/branding/revancify/monochromeicon/drawable/ic_app_icons_themed_youtube_music.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/src/main/resources/music/settings/host/values/strings.xml b/src/main/resources/music/settings/host/values/strings.xml new file mode 100644 index 000000000..056c0592a --- /dev/null +++ b/src/main/resources/music/settings/host/values/strings.xml @@ -0,0 +1,29 @@ + + + Cast button + Hides the Cast button at the top of the homepage + ADS + Design + Listening + Navigation + "Hides the music category bar at the top of the homepage +(requires an app restart)" + Compact Header + "Permanently keep the 250/251 opus codec +(requires an app restart)" + Codecs Overrides + Permanently keep player minimized even if another track is played + Permanent Minimized Player + Matches the fullscreen player color with the minimized one + Color Match Players + Sets the navigation bar color to black + Black NavBar + ReVanced settings + "Shows ads before playing a track +(requires an app restart)" + Enable ADS (to support artists) + "Unlocks landscape mode +(requires an app restart)" + Tablet Mode + Website + diff --git a/src/main/resources/music/settings/host/xml/settings_headers.xml b/src/main/resources/music/settings/host/xml/settings_headers.xml new file mode 100644 index 000000000..0515ac560 --- /dev/null +++ b/src/main/resources/music/settings/host/xml/settings_headers.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/music/settings/host/xml/settings_prefs_compat.xml b/src/main/resources/music/settings/host/xml/settings_prefs_compat.xml new file mode 100644 index 000000000..fe08b30ab --- /dev/null +++ b/src/main/resources/music/settings/host/xml/settings_prefs_compat.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/music/translate/values-ar-v21/strings.xml b/src/main/resources/music/translate/values-ar-v21/strings.xml new file mode 100644 index 000000000..226c93ba1 --- /dev/null +++ b/src/main/resources/music/translate/values-ar-v21/strings.xml @@ -0,0 +1,26 @@ + + + زر البث + إخفاء زر البث في الجزء العلوي من الصفحة الرئيسية + الإعلانات + التصميم + الاستماع + التنقل + "إخفاء شريط فئة الموسيقى أعلى الصفحة الرئيسية +(يتطلب إعادة تشغيل التطبيق)" + تصغير الرأس + "احتفظ دائمًا ببرنامج الترميز 250/251 opus +(يتطلب إعادة تشغيل التطبيق)" + إبقاء المشغل مصغرًا بشكل دائم حتى إذا تم تشغيل مسار آخر + قم بمطابقة لون المشغل في وضع ملء الشاشة مع المشغل المصغر + مطابقة ألوان المشغل + تعيين لون شريط التنقل إلى اللون الأسود + شريط التنقل الأسود + (ReVanced) إعدادات + "إظهار الإعلانات قبل تشغيل المسار +(يتطلب إعادة تشغيل التطبيق)" + تمكين الإعلانات (لدعم الفنانين) + "فتح الوضع الأفقي +(يتطلب إعادة تشغيل التطبيق)" + وضع الجهاز اللوحي + diff --git a/src/main/resources/music/translate/values-az-rAZ-v21/strings.xml b/src/main/resources/music/translate/values-az-rAZ-v21/strings.xml new file mode 100644 index 000000000..f94758e59 --- /dev/null +++ b/src/main/resources/music/translate/values-az-rAZ-v21/strings.xml @@ -0,0 +1,29 @@ + + + Yayım düyməsi + Əsas səhifənin yuxarısındakı Yayım düyməsini gizlədir + Reklamlar + Dizayn + Dinləmə + Naviqasiya + "Əsas səhifənin ən üstündəki musiqi kateqoriya sətrini gizlədir +(yenidən başlatma lazımdır)" + Yığcam başlıq + "250/251 opus kodekini daimi olaraq saxlayın +(tətbiqin yenidən başlaması tələb olunur)" + Codec ləğvi + Başqa bir trek çalınsa belə, pleyeri daima minimuma endirin + Daimi Minimallaşdırılmış Pleyer + Tam ekran oynadıcının rəngi, kiçildilmiş oynadıcının rəngiylə eyni olacaq + Eyni rəngli oynadıcılar + Hərəkət sətrinin rəngini qara olaraq tənzimləyir + Qara rəngli hərəkət xətti + ReVanced tənzimləmələri + "Bir musiqi oxudulmazdan əvvəl reklamın göstərilməsi +(yenidən başlatmaq lazımdır)" + Reklamları aktivləşdir (sənətkarları dəstəkləmək üçün) + "Üfüqi rejimin kilidini açar +(yenidən başlatma lazımdır)" + Planşet rejimi + Web sayt + diff --git a/src/main/resources/music/translate/values-bg-rBG-v21/strings.xml b/src/main/resources/music/translate/values-bg-rBG-v21/strings.xml new file mode 100644 index 000000000..10883f4d3 --- /dev/null +++ b/src/main/resources/music/translate/values-bg-rBG-v21/strings.xml @@ -0,0 +1,26 @@ + + + Cast button + Hides the Cast button at the top of the homepage + Реклами + Дизайн + Слушане + Навигация + "Скрива лентата с категории музика в горната част на началната страница +(изисква рестартиране на приложението)" + Компактна заглавка + "Permanently keep the 250/251 opus codec +(requires an app restart)" + Permanently keep player minimized even if another track is played + Цветът на плейъра на цял екран съответства с цвета на минимизирания + Еднакъв цвят на плейърите + Задава цвета на лентата за навигация на черен + Черна лента за навигация + Настройки на ReVanced + "Показва реклами преди пускане на песен +(изисква рестартиране на приложението)" + Активиране на рекламите (за подкрепа на изпълнителите) + "Отключва пейзажен режим +(изисква рестартиране на приложението)" + Режим на таблет + diff --git a/src/main/resources/music/translate/values-bn-rIN-v21/strings.xml b/src/main/resources/music/translate/values-bn-rIN-v21/strings.xml new file mode 100644 index 000000000..e71eae027 --- /dev/null +++ b/src/main/resources/music/translate/values-bn-rIN-v21/strings.xml @@ -0,0 +1,26 @@ + + + কাস্ট বোতাম + হোমপেইজ থেকে কাস্ট বাটন লুকাবে + বিজ্ঞাপন + ডিজাইন + শুনছেন + নেভিগেশন + "হোমপেজের উপরে মিউজিক ক্যাটাগরি বার লুকিয়ে রাখে +(অ্যাপটিকে রিস্টার্ট করা প্রয়োজন)" + সংকুচিত হেডার + "স্থায়ীভাবে 250/251 অপাস কোডেক রাখুন +(অ্যাপটিকে রিস্টার্ট করা প্রয়োজন)" + যদি অন্য ট্রাক বাজানো হয়, তাও প্লেয়ারকে স্থায়ীভাবে ছোট করে রাখুন + পূর্ণস্ক্রীন প্লেয়ারের রঙ মিনিমাইজড প্লেয়ারের রঙের সঙ্গে মিলবে + রঙ মিলিয়ে প্লেয়ার + নেভিগেশন বারের রঙ কালো সেট করবে + কালো নেভিগশন বার + রি ভেন্সড সেটিংস + "একটি ট্রাক শুরু হওয়ার আগে বিজ্ঞাপন দেখাবে +(অ্যাপটিকে রিস্টার্ট করা প্রয়োজন)" + বিজ্ঞাপন সক্রিয় করুন (শিল্পীদের সাহায্য করতে) + "ল্যান্ডস্কেপ মোড আনলক করুন +(অ্যাপটিকে রিস্টার্ট করা প্রয়োজন)" + ট্যাবলেট মোড + diff --git a/src/main/resources/music/translate/values-bn-v21/strings.xml b/src/main/resources/music/translate/values-bn-v21/strings.xml new file mode 100644 index 000000000..126742527 --- /dev/null +++ b/src/main/resources/music/translate/values-bn-v21/strings.xml @@ -0,0 +1,27 @@ + + + কাস্ট বাটন + হোমপেইজ থেকে কাস্ট বাটন লুকান + অ্যাডস + ডিজাইন + শুনছেন + নেভিগেশন + "মিউজিক ক্যাটাগোরি বার হাইড রাখুন হোম পেজে +(অ্যাপ রিস্টার্ট প্রয়োজন)" + সংক্ষিপ্ত শিরোনাম + "স্থায়ীভাবে ২৫০/২৫১ অপাস কোডেক রাখুন +(অ্যাপটি রিস্টার্ট করেনিতে হবে)" + স্থায়ীভাবে প্লেয়ার ছোট রাখুন এমনকি যদি অন্য ট্র্যাক বাজানো হয় + পূর্ণস্ক্রীন প্লেয়ারের রঙের সাথে মিনিমাইজ করা রং মেলান + কালার ম্যাচ প্লেয়ার + নেভিগেশন বারের রঙ কালো সেট করুন + ব্যাক নেভিগেশন-বার + রিভ্যান্সড সেটিংস + "একটি ট্র্যাক প্লে করার আগে বিজ্ঞাপন দেখুন +(অ্যাপটি পুনরায় চালু করতে হবে)" + অ্যাডস চালু করুন (শিল্পীদের সমর্থন করতে) + "ল্যান্ডস্কেপ মোড আনলক করুন +(অ্যাপটি একবার রিস্টার্ট প্রয়োজন)" + ট্যাবলেট মোড + ওয়েবসাইট + diff --git a/src/main/resources/music/translate/values-cs-rCZ-v21/strings.xml b/src/main/resources/music/translate/values-cs-rCZ-v21/strings.xml new file mode 100644 index 000000000..c90bdb490 --- /dev/null +++ b/src/main/resources/music/translate/values-cs-rCZ-v21/strings.xml @@ -0,0 +1,26 @@ + + + Cast button + Hides the Cast button at the top of the homepage + REKLAMY + Vzhled + Poslech + Navigace + "Skryje panel kategorií hudby v horní části domovské stránky +(vyžaduje restart aplikace)" + Kompaktní záhlaví + "Permanently keep the 250/251 opus codec +(requires an app restart)" + Permanently keep player minimized even if another track is played + Sjednotí barvu celoobrazovkového přehrávače s minimalizovaným přehrávačem v aplikaci + Barevné sjednocení přehrávačů + Nastaví barvu navigačního panelu na černou + Černý navigační panel + Nastavení ReVanced + "Před přehráváním skladby zobrazit reklamy +(vyžaduje restart aplikace)" + Povolit REKLAMY (pro podporu umělců) + "Odemkne režim na šířku +(vyžaduje restart aplikace)" + Režim tabletu + diff --git a/src/main/resources/music/translate/values-de-rDE-v21/strings.xml b/src/main/resources/music/translate/values-de-rDE-v21/strings.xml new file mode 100644 index 000000000..57db3610b --- /dev/null +++ b/src/main/resources/music/translate/values-de-rDE-v21/strings.xml @@ -0,0 +1,27 @@ + + + Cast-Symbol + Versteckt das Cast-Symbol oben auf der Startseite + Werbung + Design + Wird gehört + Navigation + "Versteckt die Leiste mit den Musikkategorien am oberen Ende der Startseite +(erfordert einen Neustart der App)" + Kompakte Überschriften + "Behalte den 250/251 Opus Codec dauerhaft +(erfordert einen Neustart der App)" + Den Player dauerhaft minimieren, selbst wenn ein anderer Track abgespielt wird + Gleicht die Farben des Vollbild- und des Miniplayers an + Farbe der Player angleichen + Setzt die Farbe der Navigationsleiste zu schwarz + Schwarze Navigationsleiste + ReVanced Einstellungen + "Werbung vor Start eines Liedes anzeigen +(erfordert einen Neustart der App)" + Werbung aktivieren (zur Unterstützung der Musiker) + "Schaltet Querformat frei +(erfordert einen Neustart der App)" + Tablet-Modus + Webseite + diff --git a/src/main/resources/music/translate/values-el-rGR-v21/strings.xml b/src/main/resources/music/translate/values-el-rGR-v21/strings.xml new file mode 100644 index 000000000..bb615c3f0 --- /dev/null +++ b/src/main/resources/music/translate/values-el-rGR-v21/strings.xml @@ -0,0 +1,27 @@ + + + Πλήκτρο μετάδοσης + Hides the Cast button at the top of the homepage + Διαφημίσεις + Σχεδίαση + Αναπαραγωγή + Πλοήγηση + "Απόκρυψη της γραμμής κορυφαίων κατηγοριών μουσικής στην κορυφή της αρχικής οθόνης +(απαιτείται επανεκκίνηση της εφαρμογής για να εφαρμοστεί η ρύθμιση)" + Απλούστευση άνω οθόνης + "Permanently keep the 250/251 opus codec +(requires an app restart)" + Permanently keep player minimized even if another track is played + Το χρώμα της πλήρους οθόνης αναπαραγωγής θα τεριάζει με το χρώμα της ελαχιστοποιημένης οθόνης αναπαραγωγής + Τέριασμα χρωμάτων οθόνης αναπαραγωγής + Ορισμός του χρώματος της γραμμής πλοήγησης σε μαύρο + Μαύρη Γραμμή Πλοήγησης + Ρυθμίσεις του ReVanced + "Εμφάνιση διαφημίσεων πριν την αναπαραγωγή ενός κομματιού +(για να υποστηρίξετε τους καλλιτέχνες, απαιτείται επανεκκίνηση της εφαρμογής)" + Ενεργοποίηση διαφημίσεων + "Ξεκλείδωμα λειτουργίας οριζόντιου προσανατολισμού +(απαιτείται επανεκκίνηση της εφαρμογής)" + Λειτουργία ως ταμπλετ + Ιστοσελίδα + diff --git a/src/main/resources/music/translate/values-es-rES-v21/strings.xml b/src/main/resources/music/translate/values-es-rES-v21/strings.xml new file mode 100644 index 000000000..3b533b6aa --- /dev/null +++ b/src/main/resources/music/translate/values-es-rES-v21/strings.xml @@ -0,0 +1,29 @@ + + + Botón de transmisión + Oculta el botón Emitir en la parte superior de la página de inicio + Publicidad + Diseño + Escuchando + Navegación + "Oculta la barra de categoría de música en la parte superior de la página de inicio +(requiere reiniciar la aplicación)" + Encabezado compacto + "Mantener permanentemente el código de 250/251 opus +(requiere un reinicio de aplicación)" + Reemplazo de códecs + Mantener permanentemente el reproductor minimizado incluso si se reproduce otra pista + Reproductor minimizado permanente + Coincide el color del reproductor a pantalla completa con el de minimizado + Coincidir colores en el reproductor + Establece el color de la barra de navegación a negro + Barra de navegación negra + Ajustes ReVanced + "Muestra anuncios antes de reproducir una canción +(requiere reiniciar la aplicación)" + Activar anuncios (para apoyar artistas) + "Desbloquea el modo horizontal +(requiere reiniciar la aplicación)" + Modo tablet + Sitio web + diff --git a/src/main/resources/music/translate/values-fi-rFI-v21/strings.xml b/src/main/resources/music/translate/values-fi-rFI-v21/strings.xml new file mode 100644 index 000000000..af1e05bed --- /dev/null +++ b/src/main/resources/music/translate/values-fi-rFI-v21/strings.xml @@ -0,0 +1,21 @@ + + + MAINOKSET + Tyyli + Kuunnellaan + Navigointi + "Piilottaa musiikin kategoriapalkin kotisivun yläreunassa +(vaatii sovelluksen uudelleenkäynnistyksen)" + Kompakti ylätunniste + Täsmää koko näytön soittimen värin pienennetyn kanssa + Täsmää soittimien värit + Asettaa navigointipalkin värin mustaksi + Musta navigointipalkki + ReVanced-asetukset + "Näytä mainokset ennen kappaleen soittamista +(vaatii sovelluksen uudelleenkäynnistyksen)" + Ota MAINOKSET käyttöön (artistien tukemista varten) + "Avaa vaakatilan lukituksen +(vaatii sovelluksen uudelleenkäynnistyksen)" + Tablettitila + diff --git a/src/main/resources/music/translate/values-fr-rFR-v21/strings.xml b/src/main/resources/music/translate/values-fr-rFR-v21/strings.xml new file mode 100644 index 000000000..9ea9d6164 --- /dev/null +++ b/src/main/resources/music/translate/values-fr-rFR-v21/strings.xml @@ -0,0 +1,29 @@ + + + Partager + Supprimer le bouton partage en haut de la page d\'accueil + Publicité + Design + En écoute + Navigation + "Supprimer la catégorie musique dans la barre du haut sur la page d'accueil +(redémarrage de l'application nécessaire)" + Barre du haut compacte + "Conserver en permanence le codec opus 250/251 +(nécessite un redémarrage de l'application)" + Remplacements de codecs + Garder en permanence le lecteur minimisé même si une autre piste est lue + Lecteur miniature permanent + Correspondre la couleur du lecteur plein écran avec celle réduite + Correspondance de la couleur des lecteurs + Changer la barre de navigation colorée en noire + Barre de navigation noire + Paramètres Revanced + "Montrer les publicités avant la lecture de la vidéo +(redémarrage de l'application nécessaire)" + Autoriser la publicité (pour supporter les artistes) + "Débloquer le mode paysage +(redémarrage de l'application nécessaire)" + Mode tablette + Site web + diff --git a/src/main/resources/music/translate/values-hi-rIN-v21/strings.xml b/src/main/resources/music/translate/values-hi-rIN-v21/strings.xml new file mode 100644 index 000000000..2813b8296 --- /dev/null +++ b/src/main/resources/music/translate/values-hi-rIN-v21/strings.xml @@ -0,0 +1,27 @@ + + + कास्ट बटन + होमपेज के शीर्ष से कास्ट बटन छुपाएं + विज्ञापन + डिज़ाइन + सुनना + नेविगेशन + "मुखपृष्ठ के शीर्ष पर से संगीत श्रेणी बार को छुपाता है +(ऐप फिरसे चालू होगा)" + कॉम्पैक्ट हेडर + "Opus codec को 250/251 पर हमेशा के लिए सेट करे +(ऐप दुबारा खुलेगा)" + प्लेयर को स्थायी रूप से छोटा रखें, भले ही दूसरा ट्रैक चल जाए + फ़ुलस्क्रीन प्लेयर का रंग मिनिमाइज़ वाले से मेल खाता है + रंग मिलान प्लेयर + नेविगेशन बार का रंग काला सेट करता है + ब्लैक नवबार + ReVanced सेटिंग्स + "ट्रैक चलाने से पहले विज्ञापन दिखाए +(ऐप रीस्टार्ट करने की आवश्यकता है)" + विज्ञापन चालू करें (कलाकारों का समर्थन करने के लिए) + "लैंडस्केप मोड को अनलॉक करता है +(ऐप को पुनरारंभ करने की आवश्यकता है)" + टैबलेट मोड + वेबसाइट + diff --git a/src/main/resources/music/translate/values-hu-rHU-v21/strings.xml b/src/main/resources/music/translate/values-hu-rHU-v21/strings.xml new file mode 100644 index 000000000..a8d382340 --- /dev/null +++ b/src/main/resources/music/translate/values-hu-rHU-v21/strings.xml @@ -0,0 +1,26 @@ + + + Átküldés gomb + Elrejti az Átküldés gombot a kezdőlap tetején + REKLÁMOK + Dizájn + Billenőkapcsolók + Navigáció + "Elrejti a zenei kategória sávot a kezdőlap tetején +(alkalmazás újraindítása szükséges)" + Kompakt fejléc + "A 250/251 opus kodek végleges megőrzése +(alkalmazás újraindítása szükséges)" + Tartsa a lejátszót minimalizálva, még akkor is, ha másik zeneszámot játszanak le + Megfelel a teljes képernyős lejátszó színének, a kicsinyített színnel + Színes lejátszó + A navigációs sáv színét feketére állíthatja + Fekete NavBar + ReVanced beállítások + "Reklámok megjelenítése a szám lejátszása előtt +(alkalmazás újraindítása szükséges)" + Reklámok megjelenítése (támogatssa a művészeket) + "Feloldja a fekvő módot +(alkalmazás újraindítása szükséges)" + Tablet Mód + diff --git a/src/main/resources/music/translate/values-id-rID-v21/strings.xml b/src/main/resources/music/translate/values-id-rID-v21/strings.xml new file mode 100644 index 000000000..f9a103397 --- /dev/null +++ b/src/main/resources/music/translate/values-id-rID-v21/strings.xml @@ -0,0 +1,29 @@ + + + Tombol transmisi + Sembunyikan tombol transmisi di bagian atas beranda + Iklan + Desain + Mendengarkan + Navigasi + "Sembunyikan bilah kategori musik di bagian atas halaman utama +(memuat ulang aplikasi diperlukan)" + Header Sederhana + "Simpan codec 250/251 opus secara permanen +(muat ulang aplikasi diperlukan)" + Penggantian codec + Tetap buka pemutar minimal meski lagu lain dimainkan + Pemutar minimal permanen + Samakan warna pemutar layar penuh dengan warna pemutar yang diminimalkan + Penyamaan warna pemutar + Mengubah warna bilah navigasi menjadi hitam + Bilah navigasi hitam + Pengaturan ReVanced + "Tampilkan iklan sebelum memutar lagu +(memuat ulang aplikasi diperlukan)" + Aktifkan Iklan (untuk mendukung artis) + "Buka mode lanskap +(memuat ulang aplikasi diperlukan)" + Mode Tablet + Website + diff --git a/src/main/resources/music/translate/values-in-v21/strings.xml b/src/main/resources/music/translate/values-in-v21/strings.xml new file mode 100644 index 000000000..f9a103397 --- /dev/null +++ b/src/main/resources/music/translate/values-in-v21/strings.xml @@ -0,0 +1,29 @@ + + + Tombol transmisi + Sembunyikan tombol transmisi di bagian atas beranda + Iklan + Desain + Mendengarkan + Navigasi + "Sembunyikan bilah kategori musik di bagian atas halaman utama +(memuat ulang aplikasi diperlukan)" + Header Sederhana + "Simpan codec 250/251 opus secara permanen +(muat ulang aplikasi diperlukan)" + Penggantian codec + Tetap buka pemutar minimal meski lagu lain dimainkan + Pemutar minimal permanen + Samakan warna pemutar layar penuh dengan warna pemutar yang diminimalkan + Penyamaan warna pemutar + Mengubah warna bilah navigasi menjadi hitam + Bilah navigasi hitam + Pengaturan ReVanced + "Tampilkan iklan sebelum memutar lagu +(memuat ulang aplikasi diperlukan)" + Aktifkan Iklan (untuk mendukung artis) + "Buka mode lanskap +(memuat ulang aplikasi diperlukan)" + Mode Tablet + Website + diff --git a/src/main/resources/music/translate/values-it-rIT-v21/strings.xml b/src/main/resources/music/translate/values-it-rIT-v21/strings.xml new file mode 100644 index 000000000..c69950823 --- /dev/null +++ b/src/main/resources/music/translate/values-it-rIT-v21/strings.xml @@ -0,0 +1,29 @@ + + + Pulsante di trasmissione + Nascondi il pulsante di trasmissione in cima alla home + Pubblicità + Aspetto + Ascolto + Navigazione + "Nasconde la barra delle categorie musicali nella parte superiore della pagina principale +(richiede un riavvio dell'app)" + Intestazione Compatta + "Mantieni permanentemente il codec opus 250/251 +(richiede un riavvio dell'app)" + Sovrascrivi Codec + Mantieni il riproduttore minimizzato anche se venisse riprodotta una traccia differente + Pulsante Riproduttore Minimizzato permanente + Allinea il colore del lettore a schermo intero con quello in secondo piano + Corrispondenza Colore Lettori + Imposta il colore della barra di navigazione su nero + NavBar Nera + Impostazioni di ReVanced + "Mostra gli annunci prima di riprodurre una traccia +(richiede un riavvio dell'app)" + Attiva Pubblicità (per supportare gli artisti) + "Sblocca la modalità orizzontale +(richiede un riavvio dell'app)" + Modalità Tablet + Sito web + diff --git a/src/main/resources/music/translate/values-ja-rJP-v21/strings.xml b/src/main/resources/music/translate/values-ja-rJP-v21/strings.xml new file mode 100644 index 000000000..897344c10 --- /dev/null +++ b/src/main/resources/music/translate/values-ja-rJP-v21/strings.xml @@ -0,0 +1,28 @@ + + + キャストボタン + ページ上部のCastボタンを非表示 + 広告 + デザイン + 再生 + ナビゲーション + "ホームページの上部にある音楽カテゴリバーを非表示にします +(アプリの再起動が必要です)" + コンパクトなヘッダー + "\"250/251 opusコーデックを常に保持(要アプリ再起動)" + コーデックの上書き + 他のトラックが再生されてもプレイヤーを常に最小化 + 常に最小化されたプレイヤー + 全画面のプレイヤーとアプリ内のミニプレイヤーの色を同じにします + プレイヤーの色を統一 + ナビゲーションバーの色を黒に設定します + 黒いナビゲーションバー + ReVanced 設定 + "トラックを再生する前に広告を表示します +(アプリの再起動が必要です)" + 広告を有効にする (アーティストをサポートする) + "横向きモードを解除します +(アプリの再起動が必要です)" + タブレットモード + ウェブサイト + diff --git a/src/main/resources/music/translate/values-kn-rIN-v21/strings.xml b/src/main/resources/music/translate/values-kn-rIN-v21/strings.xml new file mode 100644 index 000000000..435c0534f --- /dev/null +++ b/src/main/resources/music/translate/values-kn-rIN-v21/strings.xml @@ -0,0 +1,25 @@ + + + ಕ್ಯಾಸ್ಟ್ ಬಟನ್ + ಮುಖಪುಟದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಕಾಸ್ಟ್ ಬಟನ್ ಅನ್ನು ಮರೆಮಾಡುತ್ತದೆ + ಜಾಹೀರಾತುಗಳು + ವಿನ್ಯಾಸ + ಕೇಳುವ + ನ್ಯಾವಿಗೇಶನ್ + "ಮುಖಪುಟದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ಮ್ಯೂಸಿಕ್ ವರ್ಗದ ಪಟ್ಟಿಯನ್ನು ಮರೆಮಾಡುತ್ತದೆ (ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ)" + ಕಾಂಪ್ಯಾಕ್ಟ್ ಹೆಡರ್ + "ಶಾಶ್ವತವಾಗಿ 250/251 opus codec ಅನ್ನು ಉಳಿಸು (ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ)" + ಕೊಡೆಕ್ಸ್ ಅತಿಕ್ರಮಣ + ಮತ್ತೊಂದು ಟ್ರ್ಯಾಕ್ ಅನ್ನು ಪ್ಲೇ ಮಾಡಿದರೂ ಸಹ ಶಾಶ್ವತವಾಗಿ ಪ್ಲೇಯರ್ ಅನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡು + ಶಾಶ್ವತ ಮಿನಿಮೈಸ್ಡ್ ಪ್ಲೇಯರ್ + ಫುಲ್‌ಸ್ಕ್ರೀನ್ ಪ್ಲೇಯರ್ ಬಣ್ಣವು ಮಿನಿಮೈಸ್ಡ್ ಬಣ್ಣಕ್ಕೆ ಹೊಂದಿಕೆಯಾಗುವುದು + ಬಣ್ಣ ಹೊಂದಾಣಿಕೆಯ ಪ್ಲೇಯರ್ ಗಳು + ನ್ಯಾವಿಗೇಶನ್ ಬಾರ್ ಅನ್ನು ಕಪ್ಪು ಬಣ್ಣಕ್ಕೆ ಹೊಂದಿಸುತ್ತದೆ + ಕಪ್ಪು ಬಣ್ಣದ ನ್ಯಾವಿಗೇಶನ್ ಬಾರ್ + ರಿವ್ಯಾಂಸ್ಡ್ ಸೆಟ್ಟಿಂಗ್ಸ್ + "ಟ್ರ್ಯಾಕ್ ಪ್ಲೇ ಮಾಡುವ ಮೊದಲು ಜಾಹೀರಾತುಗಳನ್ನು ತೋರಿಸುವುದು (ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ)" + ಜಾಹೀರಾತುಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸು (ಕಲಾವಿದರನ್ನು ಬೆಂಬಲಿಸಲು) + "ಅನ್ಲಾಕ್ ಲ್ಯಾಂಡ್ಸ್ಕೇಪ್ ಮೋಡ್ (ಅಪ್ಲಿಕೇಶನ್ ಮರುಪ್ರಾರಂಭದ ಅಗತ್ಯವಿದೆ)" + ಟ್ಯಾಬ್ಲೆಟ್ ಮೋಡ್ + ವೆಬ್‌ಸೈಟ್‌ + diff --git a/src/main/resources/music/translate/values-ko-rKR-v21/strings.xml b/src/main/resources/music/translate/values-ko-rKR-v21/strings.xml new file mode 100644 index 000000000..1c73e1b2c --- /dev/null +++ b/src/main/resources/music/translate/values-ko-rKR-v21/strings.xml @@ -0,0 +1,29 @@ + + + 크롬캐스트 버튼 + 홈페이지 상단에서 크롬캐스트 버튼을 숨깁니다 + 광고 + 디자인 + 청취 + 내비게이션 + "홈페이지 상단의 음악 카테고리 바를 숨깁니다 +(앱을 재시작해야 적용됨)" + 간략한 헤더 + "250/251 opus 코덱을 사용합니다 +(앱을 재시작해야 적용됨)" + 코덱 강제 설정 + 다른 트랙이 재생되더라도 플레이어를 항상 최소화 상태로 유지합니다 + 플레이어를 항상 최소화 상태로 유지 + 최소화 상태의 플레이어와 전체화면 플레이어의 색상을 통일시킵니다 + 플레이어 색상 통일 + 내비게이션 바 색상을 검정으로 설정합니다 + 검정 내비게이션 바 + ReVanced 설정 + "트랙을 재생하기 전 광고를 표시합니다 +(앱을 재시작해야 적용됨)" + 광고 활성화 (아티스트 지원) + "앱을 가로로 회전할 수 있도록 합니다 +(앱을 재시작해야 적용됨)" + 태블릿 모드 + 웹사이트 + diff --git a/src/main/resources/music/translate/values-ml-rIN-v21/strings.xml b/src/main/resources/music/translate/values-ml-rIN-v21/strings.xml new file mode 100644 index 000000000..24834b313 --- /dev/null +++ b/src/main/resources/music/translate/values-ml-rIN-v21/strings.xml @@ -0,0 +1,27 @@ + + + കാസ്റ്റ് ബട്ടൺ + ഹോം പേജിന്റെ മുകളിലുള്ള കാസ്റ്റ് ബട്ടൺ മറയ്ക്കുന്നു + പരസ്യങ്ങൾ + ഡിസൈൻ + കേൾക്കുന്നു + നാവിഗേഷൻ + "ഹോം പേജിന്റെ മുകളിലുള്ള സംഗീത വിഭാഗ ബാർ മറയ്ക്കുന്നു +(ആപ്പ് പുനരാരംഭിക്കേണ്ടതുണ്ട്)" + ഒതുക്കമുള്ള തലക്കെട്ട് + "250/251 ഓപസ് കോഡെക് ശാശ്വതമായി സൂക്ഷിക്കുക +(ആപ്പ് പുനരാരംഭിക്കേണ്ടതുണ്ട്)" + മറ്റൊരു ട്രാക്ക് പ്ലേ ചെയ്‌താലും പ്ലെയറിനെ മിനിമൈസ് ആക്കി തന്നെ നിലനിര്‍ത്തുക + ഫുൾസ്‌ക്രീൻ പ്ലെയർ നിറം ചെറുതാക്കിയതുമായി യോജിക്കുന്നു + കളർ മാച്ച് പ്ലെയേഴ്സ് + നാവിഗേഷൻ ബാറിന്റെ നിറം കറുപ്പായി സജ്ജീകരിക്കുന്നു + കറുത്ത നാവിഗേഷൻ ബാർ + ReVanced ക്രമീകരണങ്ങൾ + "ഒരു ട്രാക്ക് പ്ലേ ചെയ്യുന്നതിന് മുമ്പ് പരസ്യങ്ങൾ കാണിക്കുന്നു +(ആപ്പ് പുനരാരംഭിക്കേണ്ടതുണ്ട്)" + പരസ്യങ്ങൾ വരുത്തുക (ആർട്ടിസ്റ്റുകളെ പിന്തുണയ്ക്കാൻ) + "ലാൻഡ്‌സ്‌കേപ്പ് മോഡ് അൺലോക്ക് ചെയ്യുന്നു +(ആപ്പ് പുനരാരംഭിക്കേണ്ടതുണ്ട്)" + ടാബ്ലെറ്റ് മോഡ് + വെബ്സൈറ്റ് + diff --git a/src/main/resources/music/translate/values-nl-rNL-v21/strings.xml b/src/main/resources/music/translate/values-nl-rNL-v21/strings.xml new file mode 100644 index 000000000..c9bd5722f --- /dev/null +++ b/src/main/resources/music/translate/values-nl-rNL-v21/strings.xml @@ -0,0 +1,26 @@ + + + Cast knop + Hides the Cast button at the top of the homepage + ADVERTENTIES + Ontwerp + Luisteren + Navigatie + "De muziekcategoriebalk bovenaan de startpagina verbergen +(vereist een herstart)" + Compacte koptekst + "Permanently keep the 250/251 opus codec +(requires an app restart)" + Permanently keep player minimized even if another track is played + Komt overeen met de kleur van de volledig scherm afspeler met de geminimaliseerde + Met afspelers overeenkomende kleuren + De kleur van de navigatiebalk instellen op zwart + Zwarte navigatiebalk + ReVanced instellingen + "Advertenties weergeven voor het afspelen van een nummer +(vereist dat de app opnieuw wordt opgestart)" + Advertenties inschakelen (om makers te ondersteunen) + "Liggende modus ontgrendelen +(vereist een herstart van de app)" + Tablet modus + diff --git a/src/main/resources/music/translate/values-pa-rIN-v21/strings.xml b/src/main/resources/music/translate/values-pa-rIN-v21/strings.xml new file mode 100644 index 000000000..bc8b83930 --- /dev/null +++ b/src/main/resources/music/translate/values-pa-rIN-v21/strings.xml @@ -0,0 +1,26 @@ + + + ਕਾਸਟ + ਹੋਮਪੇਜ ਦੇ ਸਿਖਰ \'ਤੇ ਕਾਸਟ ਬਟਨ ਨੂੰ ਲੁਕਾਉਂਦਾ ਹੈ + ਵਿਗਿਆਪਨ + ਡਿਜ਼ਾਈਨ + ਸੁਣ ਰਿਹਾ ਹੈ + ਨੇਵੀਗੇਸ਼ਨ + "ਹੋਮਪੇਜ ਦੇ ਸਿਖਰ 'ਤੇ ਸੰਗੀਤ ਸ਼੍ਰੇਣੀ ਪੱਟੀ ਨੂੰ ਲੁਕਾਉਂਦਾ ਹੈ +(ਇੱਕ ਐਪ ਰੀਸਟਾਰਟ ਦੀ ਲੋੜ ਹੈ)" + ਸੰਖੇਪ ਸਿਰਲੇਖ + "250/251 ਓਪਸ ਕੋਡੇਕ ਨੂੰ ਸਥਾਈ ਤੌਰ 'ਤੇ ਰੱਖੋ +(ਇੱਕ ਐਪ ਰੀਸਟਾਰਟ ਦੀ ਲੋੜ ਹੈ)" + ਪਲੇਅਰ ਨੂੰ ਸਥਾਈ ਤੌਰ \'ਤੇ ਘੱਟ ਤੋਂ ਘੱਟ ਰੱਖੋ ਭਾਵੇਂ ਕੋਈ ਹੋਰ ਟਰੈਕ ਚਲਾਇਆ ਜਾਵੇ + ਪੂਰੀ ਸਕਰੀਨ ਪਲੇਅਰ ਦੇ ਰੰਗ ਨੂੰ ਨਿਊਨਤਮ ਕੀਤੇ ਰੰਗ ਨਾਲ ਮੇਲ ਖਾਂਦਾ ਹੈ + ਰੰਗ ਮੈਚ ਖਿਡਾਰੀ + ਨੈਵੀਗੇਸ਼ਨ ਪੱਟੀ ਦੇ ਰੰਗ ਨੂੰ ਕਾਲੇ ਤੇ ਸੈੱਟ ਕਰਦਾ ਹੈ + ਕਾਲਾ ਨਵਬਾਰ + ReVanced ਸੈਟਿੰਗ + "ਇੱਕ ਟ੍ਰੈਕ ਚਲਾਉਣ ਤੋਂ ਪਹਿਲਾਂ ਵਿਗਿਆਪਨ ਦਿਖਾਉਂਦਾ ਹੈ +(ਇੱਕ ਐਪ ਰੀਸਟਾਰਟ ਦੀ ਲੋੜ ਹੈ)" + ADS ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ (ਕਲਾਕਾਰਾਂ ਦਾ ਸਮਰਥਨ ਕਰਨ ਲਈ) + "ਲੈਂਡਸਕੇਪ ਮੋਡ ਨੂੰ ਅਨਲੌਕ ਕਰਦਾ ਹੈ +(ਇੱਕ ਐਪ ਰੀਸਟਾਰਟ ਦੀ ਲੋੜ ਹੈ)" + ਟੈਬਲੇਟ ਮੋਡ + diff --git a/src/main/resources/music/translate/values-pl-rPL-v21/strings.xml b/src/main/resources/music/translate/values-pl-rPL-v21/strings.xml new file mode 100644 index 000000000..e023897e6 --- /dev/null +++ b/src/main/resources/music/translate/values-pl-rPL-v21/strings.xml @@ -0,0 +1,26 @@ + + + Przycisk projekcji + Ukrywa przycisk projekcji znajdujący się na górnej części strony głównej + Reklamy + Design + Słuchanie + Nawigacja + "Ukrywa pasek kategorii muzyki na górze strony głównej +(wymaga ponownego uruchomienia aplikacji)" + Kompaktowy Nagłówek + "Utrzymuj kodek opus 250/251 +(wymagany restart aplikacji)" + Trwale utrzymuj odtwarzacz zminimalizowany, nawet jeśli odtwarzany jest inny utwór + Dopasuje kolor odtwarzacza w trybie pełnoekranowym do zminimalizowanego + Dopasowanie koloru odtwarzaczy + Ustawia kolor paska nawigacji na czarny + Czarny pasek nawigacji + Ustawienia ReVanced + "Pokaż reklamy przed odtwarzaniem utworu +(wymaga ponownego uruchomienia aplikacji)" + Włącz Reklamy (aby wspierać twórców) + "Odblokowuje tryb poziomy +(wymaga ponownego uruchomienia aplikacji)" + Tryb Tabletowy + diff --git a/src/main/resources/music/translate/values-pt-rBR-v21/strings.xml b/src/main/resources/music/translate/values-pt-rBR-v21/strings.xml new file mode 100644 index 000000000..bdb89e6a0 --- /dev/null +++ b/src/main/resources/music/translate/values-pt-rBR-v21/strings.xml @@ -0,0 +1,29 @@ + + + Botão Transmitir + Oculta o botão de Transmissão no topo da página inicial + Anúncios + Aparência + Ouvindo + Navegação + "Oculta a barra de categorias de música no topo da página inicial +(requer a reinicialização do aplicativo)" + Cabeçalho compacto + "Manter permanentemente os codecs de opus 250/251 +(requer a reinicialização do aplicativo)" + Substituições de codecs + Manter o player minimizado permanentemente mesmo se outra música for reproduzida + Reprodutor minimizado permanente + Corresponder à cor do player de tela cheia com a minimizada + Igualar as cores dos \"players\" + Define a cor da barra de navegação para preto + Barra de Navegação Preta + Configurações do ReVanced + "Mostrar anúncios antes de tocar uma faixa +(requer a reinicialização do aplicativo)" + Ativar anúncios (para dar suporte aos artistas) + "Desbloqueia o modo paisagem +(requer a reinicialização do aplicativo)" + Modo Tablet + Site + diff --git a/src/main/resources/music/translate/values-pt-rPT-v21/strings.xml b/src/main/resources/music/translate/values-pt-rPT-v21/strings.xml new file mode 100644 index 000000000..5dffee4d4 --- /dev/null +++ b/src/main/resources/music/translate/values-pt-rPT-v21/strings.xml @@ -0,0 +1,29 @@ + + + Botão de transmissão + Oculta o botão Transmitir no topo da página inicial + ANÚNCIOS + Design + Ouvindo + Navegação + "Oculta a barra de categorias de música no topo da página inicial +(requer reinicialização da aplicação)" + Cabeçalho compacto + "Permanentemente mantenha o codec opus 250/251 +(requer reinicialização da aplicação)" + Sobrepor codificador + Mantenha o ‘player’ permanentemente minimizado mesmo se outra música for tocada + Alternar ‘player’ minimizado permanente + Corresponde à cor do ‘player’ em ecrã cheio com o minimizado + Colour Match Players + Define a cor da barra de navegação para negro + Barra de Navegação Negra + Configurações de ReVanced + "Mostra anúncios antes de tocar uma faixa +(requer reinicialização da aplicação)" + Activar ADS (para suportar artistas) + "Desbloqueia o modo horizontal +(requer reinicialização da aplicação)" + Modo Tablet + Site + diff --git a/src/main/resources/music/translate/values-ro-rRO-v21/strings.xml b/src/main/resources/music/translate/values-ro-rRO-v21/strings.xml new file mode 100644 index 000000000..63914fecf --- /dev/null +++ b/src/main/resources/music/translate/values-ro-rRO-v21/strings.xml @@ -0,0 +1,26 @@ + + + Cast button + Hides the Cast button at the top of the homepage + Reclame + Design + Comutare Control + Navigare + "Ascunde bara de categorii pentru muzică din partea de sus a paginii de start +(necesită o repornire a aplicației)" + Antet compact + "Permanently keep the 250/251 opus codec +(requires an app restart)" + Permanently keep player minimized even if another track is played + Potrivește culoarea player-ului pe ecran întreg cu cea minimizată + Culoarea Corespunde Player-ului + Setează culoarea barei de navigare la negru + Navbar Negru + Setări ReVanced + "Arată reclame înainte de a rula o piesă +(necesită o repornire a aplicației)" + Activează Reclamele (pentru a susține artiștii) + "Deblochează modul peisaj +(necesită o repornire a aplicației)" + Mod Tabletă + diff --git a/src/main/resources/music/translate/values-ru-rRU-v21/strings.xml b/src/main/resources/music/translate/values-ru-rRU-v21/strings.xml new file mode 100644 index 000000000..23ab2d4e8 --- /dev/null +++ b/src/main/resources/music/translate/values-ru-rRU-v21/strings.xml @@ -0,0 +1,29 @@ + + + Кнопка трансляции + Скрывает кнопку трансляции в верхней части главной страницы + Реклама + Внешний вид + Прослушивание + Навигация + "Скрывает панель категорий музыки в верхней части главной страницы +(требуется перезапуск приложения)" + Компактная верхняя панель + "Постоянно использовать кодек opus 250/251 +(требуется перезапуск приложения)" + Переопределение кодека + Держать плеер свернутым, даже при переключении на другой трек + Держать плеер свернутым + Цвет свернутого плеера соответствует цвету полноэкранного плеера + Соответствие цвета плееров + Устанавливает черный цвет панели навигации + Черная панель навигации + Настройки ReVanced + "Показывает рекламу перед воспроизведением трека +(требуется перезапуск приложения)" + Включить рекламу (для поддержки исполнителей) + "Разблокирует альбомную ориентацию +(требуется перезапуск приложения)" + Режим планшета + Сайт + diff --git a/src/main/resources/music/translate/values-sk-rSK-v21/strings.xml b/src/main/resources/music/translate/values-sk-rSK-v21/strings.xml new file mode 100644 index 000000000..797a22b2c --- /dev/null +++ b/src/main/resources/music/translate/values-sk-rSK-v21/strings.xml @@ -0,0 +1,29 @@ + + + Funkcia prenosu + Skryje tlačidlo Prenosu v hornej časti domovskej stránky + Reklama + Dizajn + Počúvanie + Navigácia + "Skryje panel s kategóriami hudby v hornej časti domovskej stránky +(vyžaduje reštart aplikácie)" + Kompaktné záhlavie + "Natrvalo ponechať kodek 250/251 opus +(vyžaduje reštart aplikácie)" + Prepisy kodekov + Natrvalo udržuj prehrávač minimalizovaný, aj keď sa prehráva iná skladba + Trvalý minimalizovaný prehrávač + Porovná farbu prehrávača na celú obrazovku s farbou minimalizovaného prehrávača + Porovnanie farby prehrávačov + Nastaví farbu navigačného panela na čiernu + Čierny NavBar + Nastavenia ReVanced + "Zobrazí reklamu pred prehratím skladby +(vyžaduje reštart aplikácie)" + Povoliť reklamu (na podporu umelcov) + "Odomkne režim na šírku +(vyžaduje reštart aplikácie)" + Režim tabletu + Webstránka + diff --git a/src/main/resources/music/translate/values-sv-rFI-v21/strings.xml b/src/main/resources/music/translate/values-sv-rFI-v21/strings.xml new file mode 100644 index 000000000..49341e0f2 --- /dev/null +++ b/src/main/resources/music/translate/values-sv-rFI-v21/strings.xml @@ -0,0 +1,26 @@ + + + Cast painike + Piilottaa Cast painikkeen aloitussivun yläosasta + MAINOKSET + Tyyli + Kuunnellaan + Navigointi + "Hides the music category bar at the top of the homepage +(requires an app restart)" + Kompakti ylätunniste + "Pidä pysyvästi 250/251 opus koodekki käytössä +( vaatii sovelluksen uudelleenkäynnistyksen)" + Pidä soitin pysyvästi pienennettynä toisen kappaleen aikana + Täsmää koko näytön soittimen värin pienennetyn kanssa + Täsmää soittimien värit + Asettaa navigointipalkin värin mustaksi + Musta navigointipalkki + ReVanced-asetukset + "Näytä mainokset ennen kappaleen soittamista +(vaatii sovelluksen uudelleenkäynnistyksen)" + Ota MAINOKSET käyttöön (artistien tukemista varten) + "Avaa vaakatilan lukituksen +(vaatii sovelluksen uudelleenkäynnistyksen)" + Tablettitila + diff --git a/src/main/resources/music/translate/values-sv-rSE-v21/strings.xml b/src/main/resources/music/translate/values-sv-rSE-v21/strings.xml new file mode 100644 index 000000000..6abf6a3ee --- /dev/null +++ b/src/main/resources/music/translate/values-sv-rSE-v21/strings.xml @@ -0,0 +1,26 @@ + + + Cast knappen + Döljer Cast knappen högst upp på hemsidan + Annonser + Design + Lyssnande + Navigation + "Döljer musikkategorifältet högst upp på hemsidan +(kräver omstart av appen)" + Kompakt sidhuvud + "Behåll 250/251 opus-codec permanent +(kräver omstart av appen)" + Håll spelaren minimerad även om ett annat spår spelas + Matchar fullskärmsspelarens färg med den minimerade + Färg matcha spelare + Sätter navigeringsfältets färg till svart + Svart navigeringsfält + Vancerade inställningar + "Visar annonser innan det spelas ett spår +(kräver omstart av appen)" + Aktivera annonser (för att stödja artister) + "Låser upp landskapsläge +(kräver omstart av appen)" + Surfplatts läge + diff --git a/src/main/resources/music/translate/values-ta-rIN-v21/strings.xml b/src/main/resources/music/translate/values-ta-rIN-v21/strings.xml new file mode 100644 index 000000000..02938e309 --- /dev/null +++ b/src/main/resources/music/translate/values-ta-rIN-v21/strings.xml @@ -0,0 +1,29 @@ + + + வார்ப்பு பொத்தான் + முகப்பு பக்கத்தில் மேலே உள்ள வார்ப்பு பொத்தானை மறைக்க + விளம்பரங்கள் + வடிவமைப்பு + கேட்கின்ற + வழிசெலுத்துதல் + "முகப்பு பக்கத்தின் மேலே உள்ள இசை வகைகளை மறைக்க +(செயலி மறு தொடக்கம் தேவைப்படும்)" + கச்சிதமான தலைப்பு + "250/251 ஓபஸ் கொடெக்கை நிரந்தரமாக வைக்க +(செயலி மறு தொடக்கம் தேவைப்படும்)" + கொடெக்ஸை மீறவும் + இன்னொரு ஒலிதடம் ஒலித்தாலும் பிளேயரை நிரந்தரமாகச் சுருக்கி வைக்கவும் + நிரந்தரமாகச் சுருக்கபட்ட பிளேயர் + முழு பிளேயரின் கலரை சுருக்கப்பட்ட ஒன்றுடன் பொருத்துவதற்கு + பிளேயருக்கு பொருத்தமான கலர் + வழிசெலுத்துதல் பட்டையின் கலரை கருப்பாக வைக்க + கருப்பு வழிசெலுத்துதல் பட்டை + ரீவான்ஸ்டு அமைப்புகள் + "ஒலிதடத்தின் முன்பாக விளம்பரங்களைக் காண்பிக்க +(செயலி மறுதொடக்கம் தேவைப்படும்)" + விளம்பரங்களைச் செயல்படுத்த(கலைஞர்களை ஊக்குவிப்பதற்காக) + "லேண்ட்ஸ்கேப் முறையைச் செயல்படுத்த +(செயலி மறுதொடக்கம் தேவைப்படும்)" + கைக்கணினி முறை + இணையதளம் + diff --git a/src/main/resources/music/translate/values-th-v21/strings.xml b/src/main/resources/music/translate/values-th-v21/strings.xml new file mode 100644 index 000000000..d590372cd --- /dev/null +++ b/src/main/resources/music/translate/values-th-v21/strings.xml @@ -0,0 +1,27 @@ + + + ปุ่มสตรีมสด + ซ่อนปุ่มสตรีมสดด้านบนในหน้าเเรก + โฆษณา + ออกเเบบหน้าต่าง + การฟังเสียง + เเทบสามปุ่มด้านล่างจอ + "ซ่อนเเทบหมวดหมู่เพลงด้านบนในหน้าเเรก +(จำเป็นต้องรีเเอพ)" + ส่วนของหน้าต่างด้านบน + "บังคับ 250/251 opus codec ในเเอพ +(จำเป็นต้องรีเเอพ)" + ปล่อยให้หน้าต่างย่อของเพลงเล่นต่อไประหว่างที่เเทร็คเพลงอื่นเเทรกเข้ามา + เปลี่ยนสีหน้าต่างตัวเล่นขนาดย่อให้เข้ากับสีตัวเต็มจอ + สีหน้าต่างตัวเล่น + เปลี่ยนสีเเทบสามปุ่มด้านล่างจอให้เป็นสีดำ + เเทบสามปุ่มสีดำ + ต้องค่า ReVanced เพิ่มเติม + "เปิดให้ดูโฆษณาก่อนที่จะเล่นเเทร็คเพลง +(จำเป็นต้องรีเเอพ)" + เปิดให้ดูโฆษณา (เพื่อสร้างรายได้ให้กับศิลปิน) + "ปลดล็อคโหมดเเนวนอนของเเอพ +(จำเป็นต้องรีเเอพ)" + โหมดสำหรับเเท็บเเล็ต + Website + diff --git a/src/main/resources/music/translate/values-tr-rTR-v21/strings.xml b/src/main/resources/music/translate/values-tr-rTR-v21/strings.xml new file mode 100644 index 000000000..9212a71db --- /dev/null +++ b/src/main/resources/music/translate/values-tr-rTR-v21/strings.xml @@ -0,0 +1,28 @@ + + + Yayınlama butonu + Ana sayfanın üstündeki yayınlama butonunu gizle + Reklamlar + Tasarım + Dinleme + Gezinme + "Ana sayfanın üstündeki müzik kategorilerini kaldırır +(uygulamanın yeniden başlatılması gerekir)" + Kompakt Başlık + "Kalıcı olarak 250/251 opus kodeğini tut. +( Uygulamayı yeniden başlatmayı gerektirir)" + Kodek\'i geçersiz kılma + Başka bir parça çalınsa bile oynatıcıyı kalıcı olarak simge durumuna küçültün + Kalıcı küçültülmüş oynatıcı + Tam ekran oynatıcının rengi, küçültülmüş oynatıcının rengiyle eşleşir + Oynatıcılar Aynı Renkte + Gezinme çubuğunun rengini siyaha ayarlar + Siyah Gezinme Çubuğu + ReVanced Extended ayarları + "Bir parça çalınmadan önce reklama yer verir (uygulamanın yeniden başlatılması gerekir)" + Reklamlara İzin Ver (sanatçıları desteklemek için) + "Yatay ekran modunun kilidini kaldırır +(uygulamanın yeniden başlatılması gerekir)" + Tablet Modu + Web sitesi + diff --git a/src/main/resources/music/translate/values-uk-rUA-v21/strings.xml b/src/main/resources/music/translate/values-uk-rUA-v21/strings.xml new file mode 100644 index 000000000..6df336977 --- /dev/null +++ b/src/main/resources/music/translate/values-uk-rUA-v21/strings.xml @@ -0,0 +1,29 @@ + + + Кнопка трансляції + Приховує кнопку трансляції у верхній частині домашньої сторінки + Реклама + Дизайн + Слухає + Навігація + "Приховує панель категорій музики у верхній частині головної сторінки +(потрібен перезапуск програми)" + Компактний Заголовок + "Постійно тримати кодек opus 250/251 +(потрібне перезавантаження програми)" + Перевизначення кодека + Постійно тримати згорнутим плеєр, навіть якщо грає інший трек + Постійний мінімізований програвач + Колір згорнутого плеєра відповідає кольору повноекранного плеєра + Гравці з підбором кольору + Встановлює чорний колір навігаційної панелі + Чорна навігаційна панель + Налаштування ReVanced + "Показує рекламу перед відтворенням треку +(потрібно перезапустити додаток)" + Увімкнути ADS (для підтримки виконавців) + "Розблокує ландшафтний режим +(потрібний перезапуск програми)" + Режим планшету + Вебсайт + diff --git a/src/main/resources/music/translate/values-vi-rVN-v21/strings.xml b/src/main/resources/music/translate/values-vi-rVN-v21/strings.xml new file mode 100644 index 000000000..c9fa74f13 --- /dev/null +++ b/src/main/resources/music/translate/values-vi-rVN-v21/strings.xml @@ -0,0 +1,29 @@ + + + Truyền + Ẩn nút Truyền ở đầu trang chủ + Quảng cáo + Thiết kế + Nghe + Điều hướng + "Ẩn thanh danh mục nhạc ở đầu trang chủ +(yêu cầu khởi động lại ứng dụng)" + Tiêu đề nhỏ gọn + "Giữ vĩnh viễn mã opus 250/251 +(yêu cầu khởi động lại ứng dụng)" + Ghi đè codec + Luôn thu nhỏ trình phát ngay cả khi một bản nhạc khác được phát + Chuyển đổi trình phát thu nhỏ + Khớp màu trình phát toàn màn hình với màu thu nhỏ + Trình phát kết hợp màu sắc + Đặt màu thanh điều hướng thành màu đen + NavBar màu đen + Cài đặt ReVanced + "Hiển thị quảng cáo trước khi phát một bản nhạc +(yêu cầu khởi động lại ứng dụng)" + Bật ADS (để hỗ trợ nghệ sĩ) + "Cho phép màn hình xoay ngang +(yêu cầu khởi động lại ứng dụng)" + Chế độ máy tính bảng + Trang Web + diff --git a/src/main/resources/music/translate/values-zh-rCN-v21/strings.xml b/src/main/resources/music/translate/values-zh-rCN-v21/strings.xml new file mode 100644 index 000000000..5d1787fd2 --- /dev/null +++ b/src/main/resources/music/translate/values-zh-rCN-v21/strings.xml @@ -0,0 +1,29 @@ + + + 投屏按钮 + 隐藏主页顶部的投屏按钮 + 广告 + 外观 + 音乐偏好 + 界面 + "隐藏主页顶部的音乐分类 +(需要重启应用)" + 简洁顶栏 + "始终保持 250/251 opus 编码 +(需要重启应用)" + 编码覆盖 + 即使播放另一曲目也始终保持导航栏播放器 + 始终保持导航栏播放器 + 使导航栏播放器与全屏播放器颜色一致 + 播放器颜色统一 + 将导航栏设为黑色 + 黑色导航栏 + ReVanced 设置 + "播放曲目之前显示广告 +(需要重启应用)" + 启用广告(以支持作者) + "解锁横屏模式 +(需要重启应用)" + 平板模式 + 网站 + diff --git a/src/main/resources/music/translate/values-zh-rTW-v21/strings.xml b/src/main/resources/music/translate/values-zh-rTW-v21/strings.xml new file mode 100644 index 000000000..88c2d8329 --- /dev/null +++ b/src/main/resources/music/translate/values-zh-rTW-v21/strings.xml @@ -0,0 +1,28 @@ + + + 投放按鈕 + 隱藏首頁頂部的投放按鈕 + 廣告 + 版面 + 聆聽 + 介面 + "隱藏位於主畫面上方的音樂分類列 +(需要重新啟動程式)" + 緊湊標題 + "永久保留 250/251 opus 編解碼器(需要重新啟動程式)" + 解碼器覆寫 + 就算播放另一首曲目時也持續使用最小化播放器 + 永遠使用最小化播放器 + 讓播放列顏色和全螢幕播放器一致 + 與播放器顏色一致 + 將導航列設成黑色 + 黑色導航欄 + ReVanced 設定 + "在播放歌曲以前播放廣告 +(需要重新啟動程式)" + 啟用廣告(可以支持創作者們) + "啟用橫向模式 +(需要重新啟動程式)" + 平板模式 + 網站 + diff --git a/src/main/resources/music/website/host/xml/settings_headers.xml b/src/main/resources/music/website/host/xml/settings_headers.xml new file mode 100644 index 000000000..45af7a978 --- /dev/null +++ b/src/main/resources/music/website/host/xml/settings_headers.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/music/website/host/xml/settings_prefs_compat.xml b/src/main/resources/music/website/host/xml/settings_prefs_compat.xml new file mode 100644 index 000000000..09431f10a --- /dev/null +++ b/src/main/resources/music/website/host/xml/settings_prefs_compat.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/returnyoutubedislike/host/values/strings.xml b/src/main/resources/returnyoutubedislike/host/values/strings.xml deleted file mode 100644 index 314f5dc2d..000000000 --- a/src/main/resources/returnyoutubedislike/host/values/strings.xml +++ /dev/null @@ -1,12 +0,0 @@ - - Return YouTube Dislike - Dislikes are shown - Dislikes are not shown - - Dislikes as percentage - Dislikes shown as percentage - Dislikes shown as number - - ReturnYouTubeDislike.com - Dislike data is provided by the Return YouTube Dislike API. Tap here to learn more. - \ No newline at end of file diff --git a/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png b/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png deleted file mode 100644 index d409b544b..000000000 Binary files a/src/main/resources/settings/drawable-ldrtl-xxxhdpi/quantum_ic_arrow_back_white_24.png and /dev/null differ diff --git a/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png b/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png deleted file mode 100644 index e27034d67..000000000 Binary files a/src/main/resources/settings/drawable-xxxhdpi/quantum_ic_arrow_back_white_24.png and /dev/null differ diff --git a/src/main/resources/settings/xml/revanced_prefs.xml b/src/main/resources/settings/xml/revanced_prefs.xml deleted file mode 100644 index 9562c0097..000000000 --- a/src/main/resources/settings/xml/revanced_prefs.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/src/main/resources/sponsorblock/drawable-xxxhdpi/quantum_ic_skip_next_white_24.png b/src/main/resources/sponsorblock/drawable-xxxhdpi/quantum_ic_skip_next_white_24.png deleted file mode 100644 index 19c4929cc..000000000 Binary files a/src/main/resources/sponsorblock/drawable-xxxhdpi/quantum_ic_skip_next_white_24.png and /dev/null differ diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml b/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml deleted file mode 100644 index 76a4b8bc9..000000000 --- a/src/main/resources/sponsorblock/drawable/ic_sb_adjust.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml b/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml deleted file mode 100644 index 04cc65e40..000000000 --- a/src/main/resources/sponsorblock/drawable/ic_sb_compare.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml b/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml deleted file mode 100644 index e93574bd9..000000000 --- a/src/main/resources/sponsorblock/drawable/ic_sb_edit.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml b/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml deleted file mode 100644 index c39b9e0b8..000000000 --- a/src/main/resources/sponsorblock/drawable/ic_sb_logo.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml b/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml deleted file mode 100644 index 97db9c98d..000000000 --- a/src/main/resources/sponsorblock/drawable/ic_sb_voting.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml b/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml deleted file mode 100644 index 97796266a..000000000 --- a/src/main/resources/sponsorblock/host/layout/youtube_controls_layout.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/main/resources/sponsorblock/host/values/strings.xml b/src/main/resources/sponsorblock/host/values/strings.xml deleted file mode 100644 index 2f4838352..000000000 --- a/src/main/resources/sponsorblock/host/values/strings.xml +++ /dev/null @@ -1,142 +0,0 @@ - - - Enable SponsorBlock - SponsorBlock is a crowd-sourced system for skipping annoying parts in YouTube videos - Enable new segment adding - Switch this on to enable experimental segment adding (has button visibility issues) - What to do with different segments - General - Show a toast when skipping segment automatically - Click to see an example toast - Skip count tracking - This lets SponsorBlock leaderboard system know how much time people have saved. The extension sends a message to the server each time you skip a segment - Adjusting new segment step - This is the number of milliseconds you can move when you use the time adjustment buttons while adding new segment - Minimum segment duration - Segments shorter than the set value (in seconds) will not be skipped or shown in the player - Your private user id - This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you - Import/Export settings - This is your entire configuration that is applicable in the desktop extension in JSON. This includes your Private userID, so be sure to share this wisely. - Change API URL - The address SponsorBlock uses to make calls to the server. <b>Don\'t change this unless you know what you\'re doing.</b> - Settings were successfully imported - Failed to import settings - Failed to export settings - Cache segments locally - Frequently watched videos (eg. music videos) may store segments in app cache to make skipping segments faster - Clear SponsorBlock segments cache - Sponsor - Paid promotion, paid referrals and direct advertisements - Intermission/Intro Animation - An interval without actual content. Could be a pause, static frame, repeating animation - Endcards/Credits - Credits or when the YouTube endcards appear. Not for spoken conclusions - Interaction Reminder (Subscribe) - When there is a short reminder to like, subscribe, follow or interact with them on any free or paid platform - Unpaid/Self Promotion - When there is unpaid or self promotion. This includes specific sections about merchandise, donations, or information about who they collaborated with - Music: Non-Music Section - Only for use in music videos. Skips parts of the video not in official mixes - Filler Tangent/Jokes - Tangential scenes added only for filler or humor that are not required to understand the main content of the video. This should not include context or background details - Skipped a sponsor segment - Skipped sponsor - Skipped intro - Skipped outro - Skipped annoying reminder - Skipped self promotion - Skipped a non-music section - Skipped preview - Skipped filler - Skipped unsubmitted segment - Skip automatically - Skip automatically once - Show a skip button - Don\'t do anything - Skip segment - About - This app uses the API from SponsorBlock - Tap to learn more, and see downloads for other platforms at: sponsor.ajay.app - Integration made by JakubWeg, recoded by oSumAtrIX - Tap to skip - - Can\'t submit the segment: %s - Unable to submit segments: Status: %d %s - Can\'t submit the segment.\nRate Limited (Too many from the same user or IP) - Can\'t submit the segment.\n\n%s - Can\'t submit the segment.\nAlready exists - Segment submitted successfully - Submitting segment… - - Unable to vote for segment: Status: %d %s - Can\'t vote for segment.\nRate Limited (Too many from the same user or IP) - Can\'t vote for segment.\n\n%s - Voted successfully - Voting for segment… - Upvote - Downvote - Change category - There are no segments to vote for - Enable voting - Switch this on to enable voting. - - Choose the segment category - You\'ve disabled this category in the settings, enable it to be able to submit - New SponsorBlock segment - Set %02d:%02d:%04d as the start or end of a new segment? - start - end - now - Time the segment begins at - Time the segment ends at - Beginning of segment set - End of segment set - Are the times correct? - The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds)\nIs it ready to submit? - Mark two locations on the time bar first - Edit timing of segment manually - Do you want to edit the timing for the start or end of the segment? - Done - Invalid time given - - View guidelines - Guidelines contain tips and rules about submitting segments - There are guidelines - It\'s recommended to read the SponsorBlock guidelines before submitting any segment - Already read - Show me - - Show time without segments - This time appears in brackets next to the current time. This shows the total video duration minus any segments. - Preview/Recap - Recap of previous episodes, or a preview of what\'s coming up later in the current video or future videos in the same series. Clips should not provide additional information. - Stats - Loading.. - SponsorBlock is disabled - Your username: <b>%s</b> - Click to change your username - Unable to change username: Status: %d %s - Username successfully changed - Submissions: <b>%s</b> - You\'ve saved people from <b>%s</b> segments. - That\'s <b>%s</b> of their lives. Click to see the leaderboard - You\'ve skipped <b>%s</b> segments. - That\'s <b>%s</b>. - minutes - Are you looking for changing colors? - You can now change a category\'s color by clicking on it above. - Choose the category - Color changed - Color reset - Invalid hex code - Change - Reset - - Segments - SB Browser - - API URL changed - API URL reset - Provided API URL is invalid - diff --git a/src/main/resources/swipecontrols/drawable/ic_sc_brightness_auto.xml b/src/main/resources/swipecontrols/drawable/ic_sc_brightness_auto.xml deleted file mode 100644 index 469b33596..000000000 --- a/src/main/resources/swipecontrols/drawable/ic_sc_brightness_auto.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/main/resources/swipecontrols/drawable/ic_sc_brightness_manual.xml b/src/main/resources/swipecontrols/drawable/ic_sc_brightness_manual.xml deleted file mode 100644 index 2f6c7072d..000000000 --- a/src/main/resources/swipecontrols/drawable/ic_sc_brightness_manual.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/main/resources/swipecontrols/drawable/ic_sc_volume_mute.xml b/src/main/resources/swipecontrols/drawable/ic_sc_volume_mute.xml deleted file mode 100644 index 73dc595f4..000000000 --- a/src/main/resources/swipecontrols/drawable/ic_sc_volume_mute.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/main/resources/swipecontrols/drawable/ic_sc_volume_normal.xml b/src/main/resources/swipecontrols/drawable/ic_sc_volume_normal.xml deleted file mode 100644 index 30dff4be1..000000000 --- a/src/main/resources/swipecontrols/drawable/ic_sc_volume_normal.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/src/main/resources/theme/values-night-v31/styles.xml b/src/main/resources/theme/values-night-v31/styles.xml deleted file mode 100644 index 53da895f8..000000000 --- a/src/main/resources/theme/values-night-v31/styles.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - diff --git a/src/main/resources/twitch/settings/xml/revanced_prefs.xml b/src/main/resources/twitch/settings/xml/revanced_prefs.xml deleted file mode 100644 index 14e1c85de..000000000 --- a/src/main/resources/twitch/settings/xml/revanced_prefs.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - \ No newline at end of file diff --git a/src/main/resources/youtube/branding/blue/launchericon/144/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/144/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..232ac9726 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/144/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..0336033a4 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/144/ic_launcher.png b/src/main/resources/youtube/branding/blue/launchericon/144/ic_launcher.png new file mode 100644 index 000000000..335906552 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/144/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/144/ic_launcher_round.png b/src/main/resources/youtube/branding/blue/launchericon/144/ic_launcher_round.png new file mode 100644 index 000000000..16b22000a Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/144/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/192/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/192/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..921904ecc Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/192/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..0eed86f40 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/192/ic_launcher.png b/src/main/resources/youtube/branding/blue/launchericon/192/ic_launcher.png new file mode 100644 index 000000000..f7fd101e9 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/192/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/192/ic_launcher_round.png b/src/main/resources/youtube/branding/blue/launchericon/192/ic_launcher_round.png new file mode 100644 index 000000000..594372e14 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/192/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/48/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/48/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..bc871f260 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/48/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..9ee376a78 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/48/ic_launcher.png b/src/main/resources/youtube/branding/blue/launchericon/48/ic_launcher.png new file mode 100644 index 000000000..1f7deb600 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/48/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/48/ic_launcher_round.png b/src/main/resources/youtube/branding/blue/launchericon/48/ic_launcher_round.png new file mode 100644 index 000000000..789bd4b6e Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/48/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/72/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/72/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..b157806cb Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/72/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..426d7208b Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/72/ic_launcher.png b/src/main/resources/youtube/branding/blue/launchericon/72/ic_launcher.png new file mode 100644 index 000000000..dde05dd12 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/72/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/72/ic_launcher_round.png b/src/main/resources/youtube/branding/blue/launchericon/72/ic_launcher_round.png new file mode 100644 index 000000000..99d0ac1b5 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/72/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/96/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/96/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..1fec49104 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/96/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/blue/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..542f30594 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/96/ic_launcher.png b/src/main/resources/youtube/branding/blue/launchericon/96/ic_launcher.png new file mode 100644 index 000000000..54dbb6536 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/96/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/blue/launchericon/96/ic_launcher_round.png b/src/main/resources/youtube/branding/blue/launchericon/96/ic_launcher_round.png new file mode 100644 index 000000000..032132dc8 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/launchericon/96/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_144.png new file mode 100644 index 000000000..af67664ce Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_192.png new file mode 100644 index 000000000..1c0618f01 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_24.png new file mode 100644 index 000000000..28f035a16 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_36.png new file mode 100644 index 000000000..d67004195 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/144/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_144.png new file mode 100644 index 000000000..d4dbe9ad1 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_192.png new file mode 100644 index 000000000..0d4e30f36 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_24.png new file mode 100644 index 000000000..96f5a25bc Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_36.png new file mode 100644 index 000000000..b4d4285c6 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/192/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_144.png new file mode 100644 index 000000000..3d8acc31a Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_192.png new file mode 100644 index 000000000..f7e7d6524 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_24.png new file mode 100644 index 000000000..1d3d1cd8d Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_36.png new file mode 100644 index 000000000..4c693a38c Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/48/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_144.png new file mode 100644 index 000000000..36ff83168 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_192.png new file mode 100644 index 000000000..55253a58e Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_24.png new file mode 100644 index 000000000..b33ee293c Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_36.png new file mode 100644 index 000000000..b054f7cf3 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/72/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_144.png new file mode 100644 index 000000000..b2f841464 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_192.png new file mode 100644 index 000000000..e06147328 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_24.png new file mode 100644 index 000000000..2aaf9e84b Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_36.png new file mode 100644 index 000000000..5a3466bd8 Binary files /dev/null and b/src/main/resources/youtube/branding/blue/splashicon/96/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/144/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/red/launchericon/144/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..3979f1ed1 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/144/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/red/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..a68256587 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/144/ic_launcher.png b/src/main/resources/youtube/branding/red/launchericon/144/ic_launcher.png new file mode 100644 index 000000000..113eebd6e Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/144/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/144/ic_launcher_round.png b/src/main/resources/youtube/branding/red/launchericon/144/ic_launcher_round.png new file mode 100644 index 000000000..549719984 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/144/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/192/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/red/launchericon/192/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..d69ca1000 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/192/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/red/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..dd6525c0d Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/192/ic_launcher.png b/src/main/resources/youtube/branding/red/launchericon/192/ic_launcher.png new file mode 100644 index 000000000..c8b042bdf Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/192/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/192/ic_launcher_round.png b/src/main/resources/youtube/branding/red/launchericon/192/ic_launcher_round.png new file mode 100644 index 000000000..a8572cacc Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/192/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/48/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/red/launchericon/48/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..dd171420f Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/48/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/red/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..c2da953cf Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/48/ic_launcher.png b/src/main/resources/youtube/branding/red/launchericon/48/ic_launcher.png new file mode 100644 index 000000000..1dfc7c1b7 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/48/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/48/ic_launcher_round.png b/src/main/resources/youtube/branding/red/launchericon/48/ic_launcher_round.png new file mode 100644 index 000000000..5c43b9a4d Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/48/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/72/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/red/launchericon/72/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..3d0ab3f7f Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/72/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/red/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..9e9c85e82 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/72/ic_launcher.png b/src/main/resources/youtube/branding/red/launchericon/72/ic_launcher.png new file mode 100644 index 000000000..16609471d Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/72/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/72/ic_launcher_round.png b/src/main/resources/youtube/branding/red/launchericon/72/ic_launcher_round.png new file mode 100644 index 000000000..86f8cde9d Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/72/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/96/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/red/launchericon/96/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..124c5565b Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/96/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/red/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..1a838b91c Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/96/ic_launcher.png b/src/main/resources/youtube/branding/red/launchericon/96/ic_launcher.png new file mode 100644 index 000000000..b52ce65fc Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/96/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/red/launchericon/96/ic_launcher_round.png b/src/main/resources/youtube/branding/red/launchericon/96/ic_launcher_round.png new file mode 100644 index 000000000..59ded0c07 Binary files /dev/null and b/src/main/resources/youtube/branding/red/launchericon/96/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/red/monochromeicon/drawable/adaptive_monochrome_ic_youtube_launcher.xml b/src/main/resources/youtube/branding/red/monochromeicon/drawable/adaptive_monochrome_ic_youtube_launcher.xml new file mode 100644 index 000000000..3cadf9916 --- /dev/null +++ b/src/main/resources/youtube/branding/red/monochromeicon/drawable/adaptive_monochrome_ic_youtube_launcher.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_144.png new file mode 100644 index 000000000..9a454fe24 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_192.png new file mode 100644 index 000000000..97c899e45 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_24.png new file mode 100644 index 000000000..48fc2b57b Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_36.png new file mode 100644 index 000000000..dc34f121f Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/144/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_144.png new file mode 100644 index 000000000..62e5cb9cb Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_192.png new file mode 100644 index 000000000..df45f2f2b Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_24.png new file mode 100644 index 000000000..3e048d8a4 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_36.png new file mode 100644 index 000000000..521a8cb38 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/192/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_144.png new file mode 100644 index 000000000..4b4164ebf Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_192.png new file mode 100644 index 000000000..61fcec440 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_24.png new file mode 100644 index 000000000..27ecdd30a Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_36.png new file mode 100644 index 000000000..c86cb7a5e Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/48/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_144.png new file mode 100644 index 000000000..192a7ea4c Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_192.png new file mode 100644 index 000000000..9a81cdef4 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_24.png new file mode 100644 index 000000000..6603c822e Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_36.png new file mode 100644 index 000000000..0b7334821 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/72/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_144.png new file mode 100644 index 000000000..63ec1878a Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_192.png new file mode 100644 index 000000000..07373d36b Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_24.png new file mode 100644 index 000000000..2c07ac290 Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_36.png new file mode 100644 index 000000000..01f5c423e Binary files /dev/null and b/src/main/resources/youtube/branding/red/splashicon/96/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/144/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/144/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..d19389745 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/144/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..c176a54cf Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/144/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/144/ic_launcher.png b/src/main/resources/youtube/branding/revancify/launchericon/144/ic_launcher.png new file mode 100644 index 000000000..65d8954d1 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/144/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/144/ic_launcher_round.png b/src/main/resources/youtube/branding/revancify/launchericon/144/ic_launcher_round.png new file mode 100644 index 000000000..65d8954d1 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/144/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/192/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/192/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..1654ce557 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/192/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..949f3cad8 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/192/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/192/ic_launcher.png b/src/main/resources/youtube/branding/revancify/launchericon/192/ic_launcher.png new file mode 100644 index 000000000..8497cce7d Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/192/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/192/ic_launcher_round.png b/src/main/resources/youtube/branding/revancify/launchericon/192/ic_launcher_round.png new file mode 100644 index 000000000..8497cce7d Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/192/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/48/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/48/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..79aa7a37a Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/48/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..d70e3081a Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/48/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/48/ic_launcher.png b/src/main/resources/youtube/branding/revancify/launchericon/48/ic_launcher.png new file mode 100644 index 000000000..ea0d7a7f3 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/48/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/48/ic_launcher_round.png b/src/main/resources/youtube/branding/revancify/launchericon/48/ic_launcher_round.png new file mode 100644 index 000000000..ea0d7a7f3 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/48/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/72/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/72/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..b0f78e9dd Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/72/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..88de191d1 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/72/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/72/ic_launcher.png b/src/main/resources/youtube/branding/revancify/launchericon/72/ic_launcher.png new file mode 100644 index 000000000..e24aacaf4 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/72/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/72/ic_launcher_round.png b/src/main/resources/youtube/branding/revancify/launchericon/72/ic_launcher_round.png new file mode 100644 index 000000000..e24aacaf4 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/72/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/96/adaptiveproduct_youtube_background_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/96/adaptiveproduct_youtube_background_color_108.png new file mode 100644 index 000000000..4b097e794 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/96/adaptiveproduct_youtube_background_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png b/src/main/resources/youtube/branding/revancify/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png new file mode 100644 index 000000000..1adce16bb Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/96/adaptiveproduct_youtube_foreground_color_108.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/96/ic_launcher.png b/src/main/resources/youtube/branding/revancify/launchericon/96/ic_launcher.png new file mode 100644 index 000000000..21a4f5541 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/96/ic_launcher.png differ diff --git a/src/main/resources/youtube/branding/revancify/launchericon/96/ic_launcher_round.png b/src/main/resources/youtube/branding/revancify/launchericon/96/ic_launcher_round.png new file mode 100644 index 000000000..21a4f5541 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/launchericon/96/ic_launcher_round.png differ diff --git a/src/main/resources/youtube/branding/revancify/monochromeicon/drawable/adaptive_monochrome_ic_youtube_launcher.xml b/src/main/resources/youtube/branding/revancify/monochromeicon/drawable/adaptive_monochrome_ic_youtube_launcher.xml new file mode 100644 index 000000000..96616c310 --- /dev/null +++ b/src/main/resources/youtube/branding/revancify/monochromeicon/drawable/adaptive_monochrome_ic_youtube_launcher.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_144.png new file mode 100644 index 000000000..177eb9a00 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_192.png new file mode 100644 index 000000000..eb7d55c79 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_24.png new file mode 100644 index 000000000..d50b0cfcd Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_36.png new file mode 100644 index 000000000..e4fe82b8e Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/144/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_144.png new file mode 100644 index 000000000..401ce884b Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_192.png new file mode 100644 index 000000000..1481c177b Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_24.png new file mode 100644 index 000000000..5898a8c64 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_36.png new file mode 100644 index 000000000..2270b5377 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/192/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_144.png new file mode 100644 index 000000000..a59995c58 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_192.png new file mode 100644 index 000000000..59ef38769 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_24.png new file mode 100644 index 000000000..02390cdc7 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_36.png new file mode 100644 index 000000000..0ba3b3bd7 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/48/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_144.png new file mode 100644 index 000000000..71456dfa1 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_192.png new file mode 100644 index 000000000..3ca0fc6b2 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_24.png new file mode 100644 index 000000000..51ccfb6c4 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_36.png new file mode 100644 index 000000000..599f7acd0 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/72/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_144.png b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_144.png new file mode 100644 index 000000000..81d0cf44e Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_144.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_192.png b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_192.png new file mode 100644 index 000000000..f5af7a106 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_192.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_24.png b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_24.png new file mode 100644 index 000000000..4e23971b3 Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_24.png differ diff --git a/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_36.png b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_36.png new file mode 100644 index 000000000..5f6f79f9a Binary files /dev/null and b/src/main/resources/youtube/branding/revancify/splashicon/96/product_logo_youtube_color_36.png differ diff --git a/src/main/resources/youtube/materialyou/drawable-night-v31/new_content_dot_background.xml b/src/main/resources/youtube/materialyou/drawable-night-v31/new_content_dot_background.xml new file mode 100644 index 000000000..2f80732c2 --- /dev/null +++ b/src/main/resources/youtube/materialyou/drawable-night-v31/new_content_dot_background.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/materialyou/drawable-v31/new_content_count_background.xml b/src/main/resources/youtube/materialyou/drawable-v31/new_content_count_background.xml new file mode 100644 index 000000000..ece2cbf17 --- /dev/null +++ b/src/main/resources/youtube/materialyou/drawable-v31/new_content_count_background.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/materialyou/drawable-v31/new_content_dot_background.xml b/src/main/resources/youtube/materialyou/drawable-v31/new_content_dot_background.xml new file mode 100644 index 000000000..71b83998d --- /dev/null +++ b/src/main/resources/youtube/materialyou/drawable-v31/new_content_dot_background.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/materialyou/host/values-v31/colors.xml b/src/main/resources/youtube/materialyou/host/values-v31/colors.xml new file mode 100644 index 000000000..1e60f04df --- /dev/null +++ b/src/main/resources/youtube/materialyou/host/values-v31/colors.xml @@ -0,0 +1,24 @@ + + + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_900 + @android:color/system_neutral1_50 + @android:color/system_neutral1_50 + @android:color/system_neutral1_50 + @android:color/system_neutral1_50 + @android:color/system_neutral1_50 + @android:color/system_neutral1_50 + diff --git a/src/main/resources/youtube/materialyou/layout-v31/new_content_count.xml b/src/main/resources/youtube/materialyou/layout-v31/new_content_count.xml new file mode 100644 index 000000000..f7f7d9450 --- /dev/null +++ b/src/main/resources/youtube/materialyou/layout-v31/new_content_count.xml @@ -0,0 +1,3 @@ + + \ No newline at end of file diff --git a/src/main/resources/youtube/overlaybuttons/drawable/playlist_repeat_button.xml b/src/main/resources/youtube/overlaybuttons/drawable/playlist_repeat_button.xml new file mode 100644 index 000000000..8e352c76c --- /dev/null +++ b/src/main/resources/youtube/overlaybuttons/drawable/playlist_repeat_button.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/overlaybuttons/drawable/playlist_shuffle_button.xml b/src/main/resources/youtube/overlaybuttons/drawable/playlist_shuffle_button.xml new file mode 100644 index 000000000..1235caa08 --- /dev/null +++ b/src/main/resources/youtube/overlaybuttons/drawable/playlist_shuffle_button.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/overlaybuttons/drawable/revanced_repeat_icon.xml b/src/main/resources/youtube/overlaybuttons/drawable/revanced_repeat_icon.xml new file mode 100644 index 000000000..017ccff06 --- /dev/null +++ b/src/main/resources/youtube/overlaybuttons/drawable/revanced_repeat_icon.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/overlaybuttons/host/layout/youtube_controls_bottom_ui_container.xml b/src/main/resources/youtube/overlaybuttons/host/layout/youtube_controls_bottom_ui_container.xml new file mode 100644 index 000000000..7fc9dcca8 --- /dev/null +++ b/src/main/resources/youtube/overlaybuttons/host/layout/youtube_controls_bottom_ui_container.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/ic_fullscreen_vertical_button.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/ic_fullscreen_vertical_button.png new file mode 100644 index 000000000..ec06da6c7 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/ic_fullscreen_vertical_button.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/ic_vr.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/ic_vr.png new file mode 100644 index 000000000..d38b24d61 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/ic_vr.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_exit_grey600_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_exit_grey600_24.png new file mode 100644 index 000000000..114ff15e4 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_exit_grey600_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_exit_white_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_exit_white_24.png new file mode 100644 index 000000000..114ff15e4 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_exit_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_grey600_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_grey600_24.png new file mode 100644 index 000000000..75342c125 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_grey600_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_white_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_white_24.png new file mode 100644 index 000000000..75342c125 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/quantum_ic_fullscreen_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_copy_icon.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_copy_icon.png new file mode 100644 index 000000000..282ff4708 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_copy_icon.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_copy_icon_with_time.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_copy_icon_with_time.png new file mode 100644 index 000000000..fad953a7f Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_copy_icon_with_time.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_download_icon.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_download_icon.png new file mode 100644 index 000000000..2915e2adc Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_download_icon.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_whitelist_icon.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_whitelist_icon.png new file mode 100644 index 000000000..33b378f25 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/revanced_whitelist_icon.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_arrow_repeat_1_white_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_arrow_repeat_1_white_24.png new file mode 100644 index 000000000..de6a4d624 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_arrow_repeat_1_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_arrow_shuffle_1_white_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_arrow_shuffle_1_white_24.png new file mode 100644 index 000000000..498f68ae9 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_arrow_shuffle_1_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_screen_full_exit_white_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_screen_full_exit_white_24.png new file mode 100644 index 000000000..114ff15e4 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_screen_full_exit_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_screen_full_white_24.png b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_screen_full_white_24.png new file mode 100644 index 000000000..75342c125 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/new/drawable-xxhdpi/yt_outline_screen_full_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/ic_fullscreen_vertical_button.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/ic_fullscreen_vertical_button.png new file mode 100644 index 000000000..39b44832e Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/ic_fullscreen_vertical_button.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/ic_vr.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/ic_vr.png new file mode 100644 index 000000000..d38b24d61 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/ic_vr.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_exit_grey600_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_exit_grey600_24.png new file mode 100644 index 000000000..9dd69e6a3 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_exit_grey600_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_exit_white_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_exit_white_24.png new file mode 100644 index 000000000..9dd69e6a3 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_exit_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_grey600_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_grey600_24.png new file mode 100644 index 000000000..7f3c4de72 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_grey600_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_white_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_white_24.png new file mode 100644 index 000000000..7f3c4de72 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/quantum_ic_fullscreen_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_copy_icon.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_copy_icon.png new file mode 100644 index 000000000..7e437b2df Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_copy_icon.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_copy_icon_with_time.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_copy_icon_with_time.png new file mode 100644 index 000000000..7b8810c0a Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_copy_icon_with_time.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_download_icon.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_download_icon.png new file mode 100644 index 000000000..27f1f088a Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_download_icon.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_whitelist_icon.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_whitelist_icon.png new file mode 100644 index 000000000..ab916ed2f Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/revanced_whitelist_icon.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_arrow_repeat_1_white_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_arrow_repeat_1_white_24.png new file mode 100644 index 000000000..317d16176 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_arrow_repeat_1_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_arrow_shuffle_1_white_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_arrow_shuffle_1_white_24.png new file mode 100644 index 000000000..12492c364 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_arrow_shuffle_1_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_screen_full_exit_white_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_screen_full_exit_white_24.png new file mode 100644 index 000000000..9dd69e6a3 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_screen_full_exit_white_24.png differ diff --git a/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_screen_full_white_24.png b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_screen_full_white_24.png new file mode 100644 index 000000000..7f3c4de72 Binary files /dev/null and b/src/main/resources/youtube/overlaybuttons/old/drawable-xxhdpi/yt_outline_screen_full_white_24.png differ diff --git a/src/main/resources/youtube/quality/host/values/arrays.xml b/src/main/resources/youtube/quality/host/values/arrays.xml new file mode 100644 index 000000000..1cb9e66dd --- /dev/null +++ b/src/main/resources/youtube/quality/host/values/arrays.xml @@ -0,0 +1,25 @@ + + + + @string/quality_auto + 144p + 240p + 360p + 480p + 720p + 1080p + 1440p + 2160p + + + -2 + 144 + 240 + 360 + 480 + 720 + 1080 + 1440 + 2160 + + diff --git a/src/main/resources/youtube/resource/host/values-af/strings.xml b/src/main/resources/youtube/resource/host/values-af/strings.xml new file mode 100644 index 000000000..e3ef3fb58 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-af/strings.xml @@ -0,0 +1,4 @@ + + + Soek + diff --git a/src/main/resources/youtube/resource/host/values-am/strings.xml b/src/main/resources/youtube/resource/host/values-am/strings.xml new file mode 100644 index 000000000..40d824a69 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-am/strings.xml @@ -0,0 +1,4 @@ + + + ፍለጋ + diff --git a/src/main/resources/youtube/resource/host/values-ar/strings.xml b/src/main/resources/youtube/resource/host/values-ar/strings.xml new file mode 100644 index 000000000..3551da3ee --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ar/strings.xml @@ -0,0 +1,4 @@ + + + بحث + diff --git a/src/main/resources/youtube/resource/host/values-az/strings.xml b/src/main/resources/youtube/resource/host/values-az/strings.xml new file mode 100644 index 000000000..0af66b334 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-az/strings.xml @@ -0,0 +1,4 @@ + + + Axtarış + diff --git a/src/main/resources/youtube/resource/host/values-b+sr+Latn/strings.xml b/src/main/resources/youtube/resource/host/values-b+sr+Latn/strings.xml new file mode 100644 index 000000000..bb57f2a92 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-b+sr+Latn/strings.xml @@ -0,0 +1,4 @@ + + + Pretraga + diff --git a/src/main/resources/youtube/resource/host/values-be/strings.xml b/src/main/resources/youtube/resource/host/values-be/strings.xml new file mode 100644 index 000000000..b90c1eafb --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-be/strings.xml @@ -0,0 +1,4 @@ + + + Шукаць + diff --git a/src/main/resources/youtube/resource/host/values-bg/strings.xml b/src/main/resources/youtube/resource/host/values-bg/strings.xml new file mode 100644 index 000000000..eeae5722f --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-bg/strings.xml @@ -0,0 +1,4 @@ + + + Търсене + diff --git a/src/main/resources/youtube/resource/host/values-bn/strings.xml b/src/main/resources/youtube/resource/host/values-bn/strings.xml new file mode 100644 index 000000000..189affb38 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-bn/strings.xml @@ -0,0 +1,4 @@ + + + সার্চ করুন + diff --git a/src/main/resources/youtube/resource/host/values-bs/strings.xml b/src/main/resources/youtube/resource/host/values-bs/strings.xml new file mode 100644 index 000000000..7a48f81fc --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-bs/strings.xml @@ -0,0 +1,4 @@ + + + Pretraži + diff --git a/src/main/resources/youtube/resource/host/values-ca/strings.xml b/src/main/resources/youtube/resource/host/values-ca/strings.xml new file mode 100644 index 000000000..4a01a2869 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ca/strings.xml @@ -0,0 +1,4 @@ + + + Cerca + diff --git a/src/main/resources/youtube/resource/host/values-cs/strings.xml b/src/main/resources/youtube/resource/host/values-cs/strings.xml new file mode 100644 index 000000000..e06536eeb --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-cs/strings.xml @@ -0,0 +1,4 @@ + + + Hledat + diff --git a/src/main/resources/youtube/resource/host/values-da/strings.xml b/src/main/resources/youtube/resource/host/values-da/strings.xml new file mode 100644 index 000000000..2ebb7673a --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-da/strings.xml @@ -0,0 +1,4 @@ + + + Søg + diff --git a/src/main/resources/youtube/resource/host/values-de/strings.xml b/src/main/resources/youtube/resource/host/values-de/strings.xml new file mode 100644 index 000000000..c1d26e5ac --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-de/strings.xml @@ -0,0 +1,4 @@ + + + Suche + diff --git a/src/main/resources/youtube/resource/host/values-el/strings.xml b/src/main/resources/youtube/resource/host/values-el/strings.xml new file mode 100644 index 000000000..f4a17dca9 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-el/strings.xml @@ -0,0 +1,4 @@ + + + Αναζήτηση + diff --git a/src/main/resources/youtube/resource/host/values-en-rGB/strings.xml b/src/main/resources/youtube/resource/host/values-en-rGB/strings.xml new file mode 100644 index 000000000..71bfebf08 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-en-rGB/strings.xml @@ -0,0 +1,4 @@ + + + Search + diff --git a/src/main/resources/youtube/resource/host/values-en-rIN/strings.xml b/src/main/resources/youtube/resource/host/values-en-rIN/strings.xml new file mode 100644 index 000000000..71bfebf08 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-en-rIN/strings.xml @@ -0,0 +1,4 @@ + + + Search + diff --git a/src/main/resources/youtube/resource/host/values-es-rUS/strings.xml b/src/main/resources/youtube/resource/host/values-es-rUS/strings.xml new file mode 100644 index 000000000..162c1c1ff --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-es-rUS/strings.xml @@ -0,0 +1,4 @@ + + + Buscar + diff --git a/src/main/resources/youtube/resource/host/values-es/strings.xml b/src/main/resources/youtube/resource/host/values-es/strings.xml new file mode 100644 index 000000000..36379bf32 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-es/strings.xml @@ -0,0 +1,4 @@ + + + Búsqueda + diff --git a/src/main/resources/youtube/resource/host/values-et/strings.xml b/src/main/resources/youtube/resource/host/values-et/strings.xml new file mode 100644 index 000000000..617cf3afa --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-et/strings.xml @@ -0,0 +1,4 @@ + + + Otsi + diff --git a/src/main/resources/youtube/resource/host/values-eu/strings.xml b/src/main/resources/youtube/resource/host/values-eu/strings.xml new file mode 100644 index 000000000..a92b02350 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-eu/strings.xml @@ -0,0 +1,4 @@ + + + Bilatu + diff --git a/src/main/resources/youtube/resource/host/values-fa/strings.xml b/src/main/resources/youtube/resource/host/values-fa/strings.xml new file mode 100644 index 000000000..c49355b3e --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-fa/strings.xml @@ -0,0 +1,4 @@ + + + جستجو + diff --git a/src/main/resources/youtube/resource/host/values-fi/strings.xml b/src/main/resources/youtube/resource/host/values-fi/strings.xml new file mode 100644 index 000000000..fc46ef91d --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-fi/strings.xml @@ -0,0 +1,4 @@ + + + Haku + diff --git a/src/main/resources/youtube/resource/host/values-fr-rCA/strings.xml b/src/main/resources/youtube/resource/host/values-fr-rCA/strings.xml new file mode 100644 index 000000000..036d06f49 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-fr-rCA/strings.xml @@ -0,0 +1,4 @@ + + + Rechercher + diff --git a/src/main/resources/youtube/resource/host/values-fr/strings.xml b/src/main/resources/youtube/resource/host/values-fr/strings.xml new file mode 100644 index 000000000..036d06f49 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-fr/strings.xml @@ -0,0 +1,4 @@ + + + Rechercher + diff --git a/src/main/resources/youtube/resource/host/values-gl/strings.xml b/src/main/resources/youtube/resource/host/values-gl/strings.xml new file mode 100644 index 000000000..162c1c1ff --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-gl/strings.xml @@ -0,0 +1,4 @@ + + + Buscar + diff --git a/src/main/resources/youtube/resource/host/values-gu/strings.xml b/src/main/resources/youtube/resource/host/values-gu/strings.xml new file mode 100644 index 000000000..c335061c9 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-gu/strings.xml @@ -0,0 +1,4 @@ + + + શોધો + diff --git a/src/main/resources/youtube/resource/host/values-hi/strings.xml b/src/main/resources/youtube/resource/host/values-hi/strings.xml new file mode 100644 index 000000000..a1741979d --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-hi/strings.xml @@ -0,0 +1,4 @@ + + + खोजें + diff --git a/src/main/resources/youtube/resource/host/values-hr/strings.xml b/src/main/resources/youtube/resource/host/values-hr/strings.xml new file mode 100644 index 000000000..7a48f81fc --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-hr/strings.xml @@ -0,0 +1,4 @@ + + + Pretraži + diff --git a/src/main/resources/youtube/resource/host/values-hu/strings.xml b/src/main/resources/youtube/resource/host/values-hu/strings.xml new file mode 100644 index 000000000..7162a2452 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-hu/strings.xml @@ -0,0 +1,4 @@ + + + Keresés + diff --git a/src/main/resources/youtube/resource/host/values-hy/strings.xml b/src/main/resources/youtube/resource/host/values-hy/strings.xml new file mode 100644 index 000000000..795c38af6 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-hy/strings.xml @@ -0,0 +1,4 @@ + + + Որոնել + diff --git a/src/main/resources/youtube/resource/host/values-in/strings.xml b/src/main/resources/youtube/resource/host/values-in/strings.xml new file mode 100644 index 000000000..083e6f534 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-in/strings.xml @@ -0,0 +1,4 @@ + + + Telusuri + diff --git a/src/main/resources/youtube/resource/host/values-is/strings.xml b/src/main/resources/youtube/resource/host/values-is/strings.xml new file mode 100644 index 000000000..7d2e8e3ef --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-is/strings.xml @@ -0,0 +1,4 @@ + + + Leita + diff --git a/src/main/resources/youtube/resource/host/values-it/strings.xml b/src/main/resources/youtube/resource/host/values-it/strings.xml new file mode 100644 index 000000000..4a01a2869 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-it/strings.xml @@ -0,0 +1,4 @@ + + + Cerca + diff --git a/src/main/resources/youtube/resource/host/values-iw/strings.xml b/src/main/resources/youtube/resource/host/values-iw/strings.xml new file mode 100644 index 000000000..f5429068c --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-iw/strings.xml @@ -0,0 +1,4 @@ + + + חיפוש + diff --git a/src/main/resources/youtube/resource/host/values-ja/strings.xml b/src/main/resources/youtube/resource/host/values-ja/strings.xml new file mode 100644 index 000000000..56410b067 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ja/strings.xml @@ -0,0 +1,4 @@ + + + 検索 + diff --git a/src/main/resources/youtube/resource/host/values-ka/strings.xml b/src/main/resources/youtube/resource/host/values-ka/strings.xml new file mode 100644 index 000000000..a72d1a4e9 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ka/strings.xml @@ -0,0 +1,4 @@ + + + ძიება + diff --git a/src/main/resources/youtube/resource/host/values-kk/strings.xml b/src/main/resources/youtube/resource/host/values-kk/strings.xml new file mode 100644 index 000000000..5905dbb15 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-kk/strings.xml @@ -0,0 +1,4 @@ + + + Іздеу + diff --git a/src/main/resources/youtube/resource/host/values-km/strings.xml b/src/main/resources/youtube/resource/host/values-km/strings.xml new file mode 100644 index 000000000..e5e1b63ab --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-km/strings.xml @@ -0,0 +1,4 @@ + + + ស្វែង​រក​ + diff --git a/src/main/resources/youtube/resource/host/values-kn/strings.xml b/src/main/resources/youtube/resource/host/values-kn/strings.xml new file mode 100644 index 000000000..57bd18300 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-kn/strings.xml @@ -0,0 +1,4 @@ + + + ಹುಡುಕಿ + diff --git a/src/main/resources/youtube/resource/host/values-ko/strings.xml b/src/main/resources/youtube/resource/host/values-ko/strings.xml new file mode 100644 index 000000000..88f8a2482 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ko/strings.xml @@ -0,0 +1,4 @@ + + + 검색 + diff --git a/src/main/resources/youtube/resource/host/values-ky/strings.xml b/src/main/resources/youtube/resource/host/values-ky/strings.xml new file mode 100644 index 000000000..bde75f61b --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ky/strings.xml @@ -0,0 +1,4 @@ + + + Издөө + diff --git a/src/main/resources/youtube/resource/host/values-lo/strings.xml b/src/main/resources/youtube/resource/host/values-lo/strings.xml new file mode 100644 index 000000000..4eaea04a0 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-lo/strings.xml @@ -0,0 +1,4 @@ + + + ຊອກຫາ + diff --git a/src/main/resources/youtube/resource/host/values-lt/strings.xml b/src/main/resources/youtube/resource/host/values-lt/strings.xml new file mode 100644 index 000000000..711743918 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-lt/strings.xml @@ -0,0 +1,4 @@ + + + Ieškoti + diff --git a/src/main/resources/youtube/resource/host/values-lv/strings.xml b/src/main/resources/youtube/resource/host/values-lv/strings.xml new file mode 100644 index 000000000..441d43fc9 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-lv/strings.xml @@ -0,0 +1,4 @@ + + + Meklēt + diff --git a/src/main/resources/youtube/resource/host/values-mk/strings.xml b/src/main/resources/youtube/resource/host/values-mk/strings.xml new file mode 100644 index 000000000..84d3739fa --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-mk/strings.xml @@ -0,0 +1,4 @@ + + + Пребарај + diff --git a/src/main/resources/youtube/resource/host/values-ml/strings.xml b/src/main/resources/youtube/resource/host/values-ml/strings.xml new file mode 100644 index 000000000..8d1fec8dd --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ml/strings.xml @@ -0,0 +1,4 @@ + + + തിരയുക + diff --git a/src/main/resources/youtube/resource/host/values-mn/strings.xml b/src/main/resources/youtube/resource/host/values-mn/strings.xml new file mode 100644 index 000000000..e25927a0f --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-mn/strings.xml @@ -0,0 +1,4 @@ + + + Хайх + diff --git a/src/main/resources/youtube/resource/host/values-mr/strings.xml b/src/main/resources/youtube/resource/host/values-mr/strings.xml new file mode 100644 index 000000000..1f95dbb2b --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-mr/strings.xml @@ -0,0 +1,4 @@ + + + शोधा + diff --git a/src/main/resources/youtube/resource/host/values-ms/strings.xml b/src/main/resources/youtube/resource/host/values-ms/strings.xml new file mode 100644 index 000000000..35bc6d500 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ms/strings.xml @@ -0,0 +1,4 @@ + + + Cari + diff --git a/src/main/resources/youtube/resource/host/values-my/strings.xml b/src/main/resources/youtube/resource/host/values-my/strings.xml new file mode 100644 index 000000000..39c011fc1 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-my/strings.xml @@ -0,0 +1,4 @@ + + + ရှာဖွေရန် + diff --git a/src/main/resources/youtube/resource/host/values-nb/strings.xml b/src/main/resources/youtube/resource/host/values-nb/strings.xml new file mode 100644 index 000000000..d6a7f4968 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-nb/strings.xml @@ -0,0 +1,4 @@ + + + Søk + diff --git a/src/main/resources/youtube/resource/host/values-ne/strings.xml b/src/main/resources/youtube/resource/host/values-ne/strings.xml new file mode 100644 index 000000000..eb3df790f --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ne/strings.xml @@ -0,0 +1,4 @@ + + + खोज्नुहोस् + diff --git a/src/main/resources/youtube/resource/host/values-nl/strings.xml b/src/main/resources/youtube/resource/host/values-nl/strings.xml new file mode 100644 index 000000000..68951d08a --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-nl/strings.xml @@ -0,0 +1,4 @@ + + + Zoeken + diff --git a/src/main/resources/youtube/resource/host/values-pa/strings.xml b/src/main/resources/youtube/resource/host/values-pa/strings.xml new file mode 100644 index 000000000..446a861d6 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-pa/strings.xml @@ -0,0 +1,4 @@ + + + ਖੋਜੋ + diff --git a/src/main/resources/youtube/resource/host/values-pl/strings.xml b/src/main/resources/youtube/resource/host/values-pl/strings.xml new file mode 100644 index 000000000..81f7dd8f0 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-pl/strings.xml @@ -0,0 +1,4 @@ + + + Szukaj + diff --git a/src/main/resources/youtube/resource/host/values-pt-rBR/strings.xml b/src/main/resources/youtube/resource/host/values-pt-rBR/strings.xml new file mode 100644 index 000000000..bd137e555 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-pt-rBR/strings.xml @@ -0,0 +1,4 @@ + + + Pesquisa + diff --git a/src/main/resources/youtube/resource/host/values-pt-rPT/strings.xml b/src/main/resources/youtube/resource/host/values-pt-rPT/strings.xml new file mode 100644 index 000000000..59e3393e1 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-pt-rPT/strings.xml @@ -0,0 +1,4 @@ + + + Pesquisar + diff --git a/src/main/resources/youtube/resource/host/values-ro/strings.xml b/src/main/resources/youtube/resource/host/values-ro/strings.xml new file mode 100644 index 000000000..79b342642 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ro/strings.xml @@ -0,0 +1,4 @@ + + + Caută + diff --git a/src/main/resources/youtube/resource/host/values-ru/strings.xml b/src/main/resources/youtube/resource/host/values-ru/strings.xml new file mode 100644 index 000000000..c996fc3bf --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ru/strings.xml @@ -0,0 +1,4 @@ + + + Поиск + diff --git a/src/main/resources/youtube/resource/host/values-si/strings.xml b/src/main/resources/youtube/resource/host/values-si/strings.xml new file mode 100644 index 000000000..edd530d72 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-si/strings.xml @@ -0,0 +1,4 @@ + + + සොයන්න + diff --git a/src/main/resources/youtube/resource/host/values-sk/strings.xml b/src/main/resources/youtube/resource/host/values-sk/strings.xml new file mode 100644 index 000000000..99b5f96df --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-sk/strings.xml @@ -0,0 +1,4 @@ + + + Hľadať + diff --git a/src/main/resources/youtube/resource/host/values-sl/strings.xml b/src/main/resources/youtube/resource/host/values-sl/strings.xml new file mode 100644 index 000000000..b934d6c38 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-sl/strings.xml @@ -0,0 +1,4 @@ + + + Iskanje + diff --git a/src/main/resources/youtube/resource/host/values-sq/strings.xml b/src/main/resources/youtube/resource/host/values-sq/strings.xml new file mode 100644 index 000000000..266a01a25 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-sq/strings.xml @@ -0,0 +1,4 @@ + + + Kërko + diff --git a/src/main/resources/youtube/resource/host/values-sr/strings.xml b/src/main/resources/youtube/resource/host/values-sr/strings.xml new file mode 100644 index 000000000..b18e20b53 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-sr/strings.xml @@ -0,0 +1,4 @@ + + + Претрага + diff --git a/src/main/resources/youtube/resource/host/values-sv/strings.xml b/src/main/resources/youtube/resource/host/values-sv/strings.xml new file mode 100644 index 000000000..e28680d19 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-sv/strings.xml @@ -0,0 +1,4 @@ + + + Sök + diff --git a/src/main/resources/youtube/resource/host/values-sw/strings.xml b/src/main/resources/youtube/resource/host/values-sw/strings.xml new file mode 100644 index 000000000..bae8e50f0 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-sw/strings.xml @@ -0,0 +1,4 @@ + + + Tafuta + diff --git a/src/main/resources/youtube/resource/host/values-ta/strings.xml b/src/main/resources/youtube/resource/host/values-ta/strings.xml new file mode 100644 index 000000000..7cc051e69 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ta/strings.xml @@ -0,0 +1,4 @@ + + + தேடு + diff --git a/src/main/resources/youtube/resource/host/values-te/strings.xml b/src/main/resources/youtube/resource/host/values-te/strings.xml new file mode 100644 index 000000000..b0cfa29d9 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-te/strings.xml @@ -0,0 +1,4 @@ + + + సెర్చ్ చేయండి + diff --git a/src/main/resources/youtube/resource/host/values-th/strings.xml b/src/main/resources/youtube/resource/host/values-th/strings.xml new file mode 100644 index 000000000..13e3b94f4 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-th/strings.xml @@ -0,0 +1,4 @@ + + + ค้นหา + diff --git a/src/main/resources/youtube/resource/host/values-tl/strings.xml b/src/main/resources/youtube/resource/host/values-tl/strings.xml new file mode 100644 index 000000000..0f4486b59 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-tl/strings.xml @@ -0,0 +1,4 @@ + + + Maghanap + diff --git a/src/main/resources/youtube/resource/host/values-tr/strings.xml b/src/main/resources/youtube/resource/host/values-tr/strings.xml new file mode 100644 index 000000000..330cbe859 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-tr/strings.xml @@ -0,0 +1,4 @@ + + + Ara + diff --git a/src/main/resources/youtube/resource/host/values-uk/strings.xml b/src/main/resources/youtube/resource/host/values-uk/strings.xml new file mode 100644 index 000000000..3337e375f --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-uk/strings.xml @@ -0,0 +1,4 @@ + + + Пошук + diff --git a/src/main/resources/youtube/resource/host/values-ur/strings.xml b/src/main/resources/youtube/resource/host/values-ur/strings.xml new file mode 100644 index 000000000..3a6bded64 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-ur/strings.xml @@ -0,0 +1,4 @@ + + + تلاش کریں + diff --git a/src/main/resources/youtube/resource/host/values-uz/strings.xml b/src/main/resources/youtube/resource/host/values-uz/strings.xml new file mode 100644 index 000000000..710e83bba --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-uz/strings.xml @@ -0,0 +1,4 @@ + + + Qidirish + diff --git a/src/main/resources/youtube/resource/host/values-vi/strings.xml b/src/main/resources/youtube/resource/host/values-vi/strings.xml new file mode 100644 index 000000000..ea59cca61 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-vi/strings.xml @@ -0,0 +1,4 @@ + + + Tìm kiếm + diff --git a/src/main/resources/youtube/resource/host/values-zh-rCN/strings.xml b/src/main/resources/youtube/resource/host/values-zh-rCN/strings.xml new file mode 100644 index 000000000..488e6b151 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-zh-rCN/strings.xml @@ -0,0 +1,4 @@ + + + 搜索 + diff --git a/src/main/resources/youtube/resource/host/values-zh-rHK/strings.xml b/src/main/resources/youtube/resource/host/values-zh-rHK/strings.xml new file mode 100644 index 000000000..162e64b2a --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-zh-rHK/strings.xml @@ -0,0 +1,4 @@ + + + 搜尋 + diff --git a/src/main/resources/youtube/resource/host/values-zh-rTW/strings.xml b/src/main/resources/youtube/resource/host/values-zh-rTW/strings.xml new file mode 100644 index 000000000..162e64b2a --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-zh-rTW/strings.xml @@ -0,0 +1,4 @@ + + + 搜尋 + diff --git a/src/main/resources/youtube/resource/host/values-zu/strings.xml b/src/main/resources/youtube/resource/host/values-zu/strings.xml new file mode 100644 index 000000000..2139b3d25 --- /dev/null +++ b/src/main/resources/youtube/resource/host/values-zu/strings.xml @@ -0,0 +1,4 @@ + + + Sesha + diff --git a/src/main/resources/youtube/resource/raw/third_party_licenses b/src/main/resources/youtube/resource/raw/third_party_licenses new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/resources/youtube/settings/host/values/strings.xml b/src/main/resources/youtube/settings/host/values/strings.xml new file mode 100644 index 000000000..7e6205a14 --- /dev/null +++ b/src/main/resources/youtube/settings/host/values/strings.xml @@ -0,0 +1,615 @@ + + + About + This app uses the API from SponsorBlock + Tap to learn more, and see downloads for other platforms at: sponsor.ajay.app + Integration made by JakubWeg + API URL changed + Provided API URL is invalid + API URL reset + API MIRROR URL changed + Provided API MIRROR URL is invalid + API MIRROR URL reset + Are you looking for changing colors? + "You can now change a category's color by clicking on it above." + Color changed + Invalid hex code + Color reset + What to do with different segments + Enable SponsorBlock + SponsorBlock is a crowd-sourced system for skipping annoying parts in YouTube videos + Enable SponsorBlock Mirror + When SponsorBlock API server is taken down, switch mirror API server to default API server + Enable new segment adding + Switch this on to enable experimental segment adding (has button visibility issues) + Enable voting + Switch this on to enable voting. + General + Adjusting new segment step + This is the number of milliseconds you can move when you use the time adjustment buttons while adding new segment + Change API URL + "The address SponsorBlock uses to make calls to the server. <b>Don't change this unless you know what you're doing.</b>" + Change API Mirror URL + "Mirror server address to switch to when SponsorBlock server is taken down. <b>Don't change this unless you know what you're doing.</b>" + Minimum segment duration + Segments shorter than the set value (in seconds) will not be skipped or shown in the player + Skip count tracking + This lets SponsorBlock leaderboard system know how much time people have saved. The extension sends a message to the server each time you skip a segment + Show a toast when skipping segment automatically + Click to see an example toast + Show time without segments + This time appears in brackets next to the current time. This shows the total video duration minus any segments. + Your private user id + This should be kept private. This is like a password and should not be shared with anyone. If someone has this, they can impersonate you + Please install MicroG + MicroG is not found + Notification settings + "1. Google device registration and Cloud Messaging need to be enabled for notifications. +2. ReVanced needs to be shown as registered under Cloud Messaging. +3. Current State in Cloud Messaging must be Connected." + MicroG settings + minutes + Choose the segment category + "The segment lasts from %02d:%02d to %02d:%02d (%d minutes %02d seconds) +Is it ready to submit?" + Are the times correct? + "You've disabled this category in the settings, enable it to be able to submit" + Do you want to edit the timing for the start or end of the segment? + Invalid time given + Done + Edit timing of segment manually + end + Mark two locations on the time bar first + start + Set %02d:%02d:%04d as the start or end of a new segment? + now + Time the segment ends at + End of segment set + Time the segment begins at + Beginning of segment set + New SponsorBlock segment + Reset + Ads related settings + Ads settings + Album cards are shown from search results + Album cards are hidden from search results + Hide album cards + Breaking news shelves are shown + Breaking news shelves are hidden + Hide breaking news shelf + Buttoned ads are shown + Buttoned ads are hidden + Hide buttoned ad + Channel guidelines are shown + Channel guidelines are hidden + Hide channel guidelines + Chapter teasers are shown + Chapter teasers are hidden + Hide chapter teaser under videos + Community guidelines are shown + Community guidelines are hidden + Hide community guidelines + Community posts are shown + Community posts are hidden + Hide community posts + Compact banners are shown + Compact banners are hidden + Hide compact banners + Filter components by their name separated by a comma + Custom filter + Emergency boxes are shown + Emergency boxes are hidden + Hide emergency boxes + General ads are shown + General ads are hidden + Hide general ads + Image shelves are shown + Image shelves are hidden + Hide image shelf + Info panels are shown + Info panels are hidden + Hide info panels + Feed surveys are shown + Feed surveys are hidden + Hide feed surveys + Latest posts are shown + Latest posts are hidden + Hide latest posts + Medical panels are shown + Medical panels are hidden + Hide medical panels + Merchandise banners are shown + Merchandise banners are hidden + Hide merchandise banners + Movies shelves are shown + Movies shelves are hidden + Hide movies shelf + Official cards are shown from search results + Official cards are hidden from search results + Hide official cards + Paid content is shown + Paid content is hidden + Hide paid content + Self sponsored cards are shown + Self sponsored cards are hidden + Hide self sponsored cards + Gray separators are shown + Gray separators are hidden + Hide gray separator + Suggestions are shown + Suggestions are hidden + Hide suggestions + Timed reactions are shown + Timed reactions are hidden + Hide timed reactions + User filter is disabled + User filter is enabled + Enable user filter + View products banner is shown + View products banner is hidden + Hide view products banner + Web search panels are shown + Web search panels are hidden + Hide web search panels + The maximum duration of media that the player will attempt to buffer + Maximum buffer size + The duration of media that must be buffered for playback to start or resume following a user action such as seeking + Playback start buffer size + The duration of media that must be buffered for playback to resume after a rebuffer + Rebuffer size + Video buffer size related settings + Video buffer settings + Select default video resolution on Cellular Network + Default video quality Cellular + Select default video resolution on Wi-Fi Network + Default video quality Wi-Fi + Select default video speed + Default video speed + is not installed. Please install it. + "Package name of the downloader app such as NewPipe's or PowerTube's" + Downloader package name + Default downloader related settings + Downloader settings + Endscreen overlay are shown + Endscreen overlay are hidden + Hide endscreen overlay + Film strip overlay are shown + Film strip overlay are hidden + Hide film strip overlay + Scrubbing haptic feedback is enabled + Scrubbing haptic feedback is disabled + Disable scrubbing haptic feedback + Seek haptic feedback is enabled + Seek haptic feedback is disabled + Disable seek haptic feedback + Chapters haptic feedback is enabled + Chapters haptic feedback is disabled + Disable chapters haptic feedback + Disable haptic feedback on long press + Disable haptic feedback + Zoom haptic feedback is enabled + Zoom haptic feedback is disabled + Disable zoom haptic feedback + Time Stamp copied to clipboard + Always auto repeat is disabled + Always auto repeat is enabled + Always auto repeat + Disable swipe gestures when player controls are visible + Enable always swipe gestures regardless of player controls visible or not + Enable always swipe gesture + Custom video speed is disabled + Custom video speed is enabled + Enable custom video speed + External browser is disabled + External browser is enabled + Enable external browser + Auto HDR brightness is disabled + Auto HDR brightness is enabled + Enable auto HDR brightness + Minimized playback is disabled + Minimized playback is enabled + Enable minimized playback + YouTube Layout will follow your Google Account status + Trick the YouTube version to force enable old layout + Enable old layout + New style quality settings are shown + Old style quality settings are shown + Enable old style quality layout + URL redirect (youtube.com/redirect) is used when opening links in video descriptions + Bypass URL redirects (youtube.com/redirect) when opening links in video descriptions + Enable open links directly + Press-to-swipe is disabled + Press-to-swipe is enabled + Enable press-to-swipe gesture + Tricks the dpi to use some phone layouts + Enable phone layout + Seekbar tapping is disabled + Does not save video quality values even when changing video quality + Save the video quality value whenever you change the video quality + Enable save video quality + Seekbar tapping is enabled + Enable seekbar tapping + Even if the brightness is set to 0 by swiping, auto brightness is not activated + When brightness reaches 0 by swiping, auto brightness is activated + Enable auto-brightness by swiping + Brightness swipe is disabled + Brightness swipe is enabled + Enable brightness gesture + Press-to-swipe haptic feedback is disabled + Press-to-swipe haptic feedback is enabled + Enable press-to-swipe haptic feedback + Volume swipe is disabled + Volume swipe is enabled + Enable volume gesture + Tablet mini-player is disabled + Tablet mini-player is enabled + Enable tablet mini-player + Tricks the dpi to use some tablet layouts + Enable tablet layout + Wide search bar is disabled + Wide search bar is enabled + Enable wide search bar + Experimental Flags + Report issues or leave suggestions here + ReVanced Extended Issue Center + ReVanced Extended settings + Extended related settings + Extended settings + Fix video playback buffer issues turned off + Fix video playback buffer issues turned on + Fix video playback buffer issues + Captions are enabled when playing a video with captioning is enforced + "Captions aren't enabled when playing a video with captioning is enforced" + Hide auto captions + Auto player popup panels are shown + Auto player popup panels are hidden + Hide auto player popup panels + Autoplay button is shown + Autoplay button is hidden + Hide autoplay button + Hides the component of the button container + Hide button container component + Clip button is shown + Clip button is hidden + Hide clip button + Create short button is shown + Create short button is hidden + Hide create short button + Dislike button is shown + Dislike button is hidden + Hide dislike button + Download button is shown + Download button is hidden + Hide download button + Like button is shown + Like button is hidden + Hide like button + Live chat button is shown + Live chat button is hidden + Hide live chat button + Playlist button is shown + Playlist button is hidden + Hide playlist button + Report button is shown + Report button is hidden + Hide report button + Share button is shown + Share button is hidden + Hide share button + Thanks button is shown + Thanks button is hidden + Hide thanks button + Captions button is shown + Captions button is hidden + Hide captions button + Cast button is shown + Cast button is hidden + Hide cast button + Channel watermark is shown + Channel watermark is hidden + Hide channel watermark + Hides the comments section or component + Hide comments component + Comment section is shown + Comment section is hidden + Hide comments section + Create button is shown + Create button is hidden + Hide create button + Crowdfunding box is shown + Crowdfunding box is hidden + Hide crowdfunding box + Email address is shown + Email address is hidden + Hide email address + Endscreen cards are shown + Endscreen cards are hidden + Hide endscreen cards + Fullscreen button container is shown + Fullscreen button container is hidden + Hide fullscreen button container + Info cards are shown + Info cards are hidden + Hide info cards + Ambient mode menu is shown + Ambient mode menu is hidden + Hide ambient mode menu + Audio track menu is shown + Audio track menu is hidden + Hide audio track menu + Captions menu is shown + Captions menu is hidden + Hide captions menu + Help & feedback menu is shown + Help & feedback menu is hidden + Hide help & feedback menu + Listening controls menu is shown + Listening controls menu is hidden + Hide listening controls menu + Listen with YouTube Music menu is shown + Listen with YouTube Music menu is hidden + Hide listen with YouTube Music menu + Loop video menu is shown + Loop video menu is hidden + Hide loop video menu + More information menu is shown + More information menu is hidden + Hide more information menu + Report menu is shown + Report menu is hidden + Hide report menu + Stats for nerds menu is shown + Stats for nerds menu is hidden + Hide stats for nerds menu + Watch in VR menu is shown + Watch in VR menu is hidden + Hide Watch in VR menu + Mix playlist is shown + Mix playlist is hidden + Hide mix playlist + Player overlay filter is shown + Player overlay filter is hidden + Hide player overlay filter + Preview comment is shown + Preview comment is hidden + Hide preview comment + Shorts button is shown + Shorts button is hidden + Hide shorts button + Hides Shorts section or the Shorts player component + Hide shorts component + Shorts player comments button is shown + Shorts player comments button is hidden + Hide shorts player comments button + Hide shorts player component + Shorts player remix button is shown + Shorts player remix button is hidden + Hide shorts player remix button + Shorts player subscriptions button is shown + Shorts player subscriptions button is hidden + Hide shorts player subscriptions button + Shorts player thanks button is shown + Shorts player thanks button is hidden + Hide shorts player thanks button + Shorts shelves are shown + Shorts shelves are hidden + Hide shorts shelf + Shorts player is disabled at app startup + Shorts player is enabled at app startup + Shorts player at app startup + Stories shelves are shown + Stories shelves are hidden + Hide stories shelf + Suggested actions shown + Suggested actions hidden + Hide suggested actions + Time and seekbar are shown + Time and seekbar are hidden + Hide time and seekbar + Bottom player layout settings + Flyout menu layout settings + Fullscreen layout settings + General layout settings + Player layout settings + Seekbar layout settings + Layout related settings + Layout settings + Miscellaneous related settings + Miscellaneous settings + Others + Auto repeat button is hidden + Auto repeat button is shown + Show auto repeat button + Copy link button is hidden + Copy link button is shown + Show copy link button + Copy link with timestamp button is hidden + Copy link with timestamp button is shown + Show copy link with timestamp button + Download button is hidden + Download button is shown + Show download button + Overlay button related settings + Overlay button settings + Whitelist button is hidden + Whitelist button is shown + Show whitelist button + Current Header: Default Header + Current Header: Premium Header + Premium Header + Information about applied patches + Patches Information + Hides the component of the player settings flyout panel + Player flyout panel component + "As this is still an experimental feature, there may be other unknown issues. +Are you sure you want to continue though?" + "Tricks the YouTube client version to v17.28.35 to load the old layout + +In the app settings, the YouTube version may be marked as v17.28.35" + "Tricks the dpi to change some layouts to phone layouts. + +If you enable this setting, the following features are available: +- Community Posts +- Hide Mix playlist" + "Fix video playback buffer issues in some regions. + +If you enable this setting, following issue may occurs: +- When playing a video in the playlist, the issue may not be fixed" + "Tricks the dpi to change some layouts to tablet layouts. + +If you enable this setting, the following features are not available: +- Ambient mode +- Community Posts" + Dislike data is provided by the True RYD Worker API. Tap here to learn more. + true-ryd.cane.workers.dev + Mirror API is disabled + Mirror API is enabled + Enable Mirror API + "True RYD Worker API uses the dislikes count exposed in the YouTube API Endpoint. + +Enable this option only for those who experience issues while using the default RYD API. + +Would you like to continue?" + True RYD Worker + Dislike data is provided by the Return YouTube Dislike API. Tap here to learn more. + ReturnYouTubeDislike.com + Dislikes shown as number + Dislikes shown as percentage + Dislikes as percentage + Dislikes are not shown + Dislikes are shown + Return YouTube Dislike + Dislikes not available (client API limit reached) + ReturnYouTubeDislike failed to confirm new user + ReturnYouTubeDislike failed to confirm vote + Dislikes temporarily not available (API timed out) + ReturnYouTubeDislike failed to register as new user + ReturnYouTubeDislike failed to send vote + Settings for Return YouTube Dislike + Return YouTube Dislike + ReVanced settings + Swipe controls related settings + Swipe controls settings + The amount of threshold for swipe to occur + Swipe magnitude threshold + The visibility of swipe overlay background + Swipe background visibility + The text size for swipe overlay + Swipe overlay text size + The amount of milliseconds the overlay is visible + Swipe overlay timeout + tool used + Video ads are shown + Video ads are hidden + Hide video ads + Failed to set quality + No internet connection + Changing default mobile data quality to: + Failed to change default mobile data quality + Changing default Wi-Fi quality to: + Failed to change default WI-FI quality + Video related settings + Video settings + Failed to add channel %s to the %s whitelist + Channel %s was added to the %s whitelist + Video Ads + Ads + Channel Name + There are no whitelisted channels + Not added to whitelist + Added to whitelist + Channel Whitelist + Failed to retrieve channel details, received code %d + Reboot to apply channel whitelist settings + Failed to remove channel %s from the %s whitelist + Channel %s was removed from the %s whitelist + Check or remove the list of channels added to the whitelist + Whitelist settings + Video Speed + Speed + SponsorBlock + SB + Sponsorblock server is not responding! + Already read + "It's recommended to read the SponsorBlock guidelines before submitting any segment" + Show me + There are guidelines + Guidelines contain tips and rules about submitting segments + View guidelines + SponsorBlock settings + SponsorBlock related settings + Switched successfully. reload the video + Switching mirror API server to main API server.. + Endcards/Credits + Credits or when the YouTube endcards appear. Not for spoken conclusions + Filler Tangent/Jokes + Tangential scenes added only for filler or humor that are not required to understand the main content of the video. This should not include context or background details + Intermission/Intro Animation + An interval without actual content. Could be a pause, static frame, repeating animation + Music: Non-Music Section + Only for use in music videos. Skips parts of the video not in official mixes + Preview/Recap + "Recap of previous episodes, or a preview of what's coming up later in the current video or future videos in the same series. Clips should not provide additional information." + Unpaid/Self Promotion + When there is unpaid or self promotion. This includes specific sections about merchandise, donations, or information about who they collaborated with + Sponsor + Paid promotion, paid referrals and direct advertisements + Interaction Reminder (Subscribe) + When there is a short reminder to like, subscribe, follow or interact with them on any free or paid platform + Failed to export settings + Import/Export settings + This is your entire configuration that is applicable in the desktop extension in JSON. This includes your Private userID, so be sure to share this wisely. + Failed to import settings + Settings were successfully imported + Skip automatically + Skip automatically once + "Don't do anything" + Show a skip button + Skip segment + Skipped outro + Skipped filler + Skipped intro + Skipped a non-music section + Skipped preview + Skipped a sponsor segment + Skipped self promotion + Skipped sponsor + Skipped annoying reminder + Skipped unsubmitted segment + Stats + Loading.. + "You've saved people from <b>%s</b> segments." + "That's <b>%s</b> of their lives. Click to see the leaderboard" + SponsorBlock is disabled + "You've skipped <b>%s</b> segments." + "That's <b>%s</b>." + Submissions: <b>%s</b> + Your username: <b>%s</b> + Click to change your username + Unable to change username: Status: %d %s + Username successfully changed + "Can't submit the segment. +Already exists" + "Can't submit the segment. + +%s" + "Can't submit the segment. +Rate Limited (Too many from the same user or IP)" + Can\'t submit the segment: %s + Unable to submit segments: Status: %d %s + Submitting segment… + Segment submitted successfully + Tap to skip + Change category + Downvote + "Can't vote for segment. + +%s" + "Can't vote for segment. +Rate Limited (Too many from the same user or IP)" + Unable to vote for segment: Status: %d %s + There are no segments to vote for + Voting for segment… + Voted successfully + Upvote + diff --git a/src/main/resources/settings/layout/revanced_settings_toolbar.xml b/src/main/resources/youtube/settings/layout/revanced_settings_toolbar.xml similarity index 79% rename from src/main/resources/settings/layout/revanced_settings_toolbar.xml rename to src/main/resources/youtube/settings/layout/revanced_settings_toolbar.xml index 86c717712..a3f474767 100644 --- a/src/main/resources/settings/layout/revanced_settings_toolbar.xml +++ b/src/main/resources/youtube/settings/layout/revanced_settings_toolbar.xml @@ -1,4 +1,4 @@ - - + + \ No newline at end of file diff --git a/src/main/resources/settings/layout/revanced_settings_with_toolbar.xml b/src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar.xml similarity index 100% rename from src/main/resources/settings/layout/revanced_settings_with_toolbar.xml rename to src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar.xml diff --git a/src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml b/src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar_layout.xml similarity index 100% rename from src/main/resources/settings/layout/revanced_settings_with_toolbar_layout.xml rename to src/main/resources/youtube/settings/layout/revanced_settings_with_toolbar_layout.xml diff --git a/src/main/resources/youtube/settings/values-v21/strings.xml b/src/main/resources/youtube/settings/values-v21/strings.xml new file mode 100644 index 000000000..cdaa87fcb --- /dev/null +++ b/src/main/resources/youtube/settings/values-v21/strings.xml @@ -0,0 +1,14 @@ + + + blue + stock + red + revancify + stock + Excluded + Included + amoled + stock + materialyou + materialyou + amoled + diff --git a/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/src/main/resources/youtube/settings/xml/revanced_prefs.xml new file mode 100644 index 000000000..0738ee8ac --- /dev/null +++ b/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/speed/host/values/arrays.xml b/src/main/resources/youtube/speed/host/values/arrays.xml new file mode 100644 index 000000000..bb2d7da2a --- /dev/null +++ b/src/main/resources/youtube/speed/host/values/arrays.xml @@ -0,0 +1,9 @@ + + + + -2 + + + @string/quality_auto + + diff --git a/src/main/resources/youtube/sponsorblock/drawable/ic_sb_adjust.xml b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_adjust.xml new file mode 100644 index 000000000..89cdd5591 --- /dev/null +++ b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_adjust.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/sponsorblock/drawable/ic_sb_compare.xml b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_compare.xml new file mode 100644 index 000000000..a682d9fb4 --- /dev/null +++ b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_compare.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/sponsorblock/drawable/ic_sb_edit.xml b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_edit.xml new file mode 100644 index 000000000..79ac2d1e5 --- /dev/null +++ b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_edit.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/sponsorblock/drawable/ic_sb_logo.xml b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_logo.xml new file mode 100644 index 000000000..52e28bfa7 --- /dev/null +++ b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_logo.xml @@ -0,0 +1,8 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/resources/sponsorblock/drawable/ic_sb_publish.xml b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_publish.xml similarity index 100% rename from src/main/resources/sponsorblock/drawable/ic_sb_publish.xml rename to src/main/resources/youtube/sponsorblock/drawable/ic_sb_publish.xml diff --git a/src/main/resources/youtube/sponsorblock/drawable/ic_sb_voting.xml b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_voting.xml new file mode 100644 index 000000000..1767e57a4 --- /dev/null +++ b/src/main/resources/youtube/sponsorblock/drawable/ic_sb_voting.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/youtube/sponsorblock/host/layout/youtube_controls_layout.xml b/src/main/resources/youtube/sponsorblock/host/layout/youtube_controls_layout.xml new file mode 100644 index 000000000..48d903b87 --- /dev/null +++ b/src/main/resources/youtube/sponsorblock/host/layout/youtube_controls_layout.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml b/src/main/resources/youtube/sponsorblock/layout/inline_sponsor_overlay.xml similarity index 100% rename from src/main/resources/sponsorblock/layout/inline_sponsor_overlay.xml rename to src/main/resources/youtube/sponsorblock/layout/inline_sponsor_overlay.xml diff --git a/src/main/resources/sponsorblock/layout/new_segment.xml b/src/main/resources/youtube/sponsorblock/layout/new_segment.xml similarity index 100% rename from src/main/resources/sponsorblock/layout/new_segment.xml rename to src/main/resources/youtube/sponsorblock/layout/new_segment.xml diff --git a/src/main/resources/sponsorblock/layout/skip_sponsor_button.xml b/src/main/resources/youtube/sponsorblock/layout/skip_sponsor_button.xml similarity index 100% rename from src/main/resources/sponsorblock/layout/skip_sponsor_button.xml rename to src/main/resources/youtube/sponsorblock/layout/skip_sponsor_button.xml diff --git a/src/main/resources/youtube/swipecontrols/drawable/ic_sc_brightness_auto.xml b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_brightness_auto.xml new file mode 100644 index 000000000..827919d70 --- /dev/null +++ b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_brightness_auto.xml @@ -0,0 +1,5 @@ + + + diff --git a/src/main/resources/youtube/swipecontrols/drawable/ic_sc_brightness_manual.xml b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_brightness_manual.xml new file mode 100644 index 000000000..567940298 --- /dev/null +++ b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_brightness_manual.xml @@ -0,0 +1,5 @@ + + + diff --git a/src/main/resources/youtube/swipecontrols/drawable/ic_sc_volume_mute.xml b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_volume_mute.xml new file mode 100644 index 000000000..d3b17332a --- /dev/null +++ b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_volume_mute.xml @@ -0,0 +1,5 @@ + + + diff --git a/src/main/resources/youtube/swipecontrols/drawable/ic_sc_volume_normal.xml b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_volume_normal.xml new file mode 100644 index 000000000..144ec4c4c --- /dev/null +++ b/src/main/resources/youtube/swipecontrols/drawable/ic_sc_volume_normal.xml @@ -0,0 +1,5 @@ + + + diff --git a/src/main/resources/youtube/translations/ar/strings.xml b/src/main/resources/youtube/translations/ar/strings.xml new file mode 100644 index 000000000..442e79040 --- /dev/null +++ b/src/main/resources/youtube/translations/ar/strings.xml @@ -0,0 +1,606 @@ + + + لمحة + هذا التطبيق يستخدم API من SponsorBlock + انقر لمعرفة المزيد؛ والتنزيل لمنصات أخرى على: sponsor.ajay.app + دُمِج بواسطة JakubWeg + هل تريد تشغيل عناصر التحكم في إمكانية الوصول لمشغل الفيديو؟ + تم تعديل عناصر التحكم الخاصة بك لأن خدمة إمكانية الوصول قيد التشغيل. + تم تغيير رابط API + رابط API غير صالح + إعادة تعيين رابط API + تم تغيير رابط API البديل + رابط API البديل غير صالح + إعادة تعيين رابط API البديل + هل تبحث عن تغيير الألوان؟ + "يمكنك الآن تغيير لون فئة عن طريق النقر عليها أعلاه." + تم تغيير اللون + رمز اللون غير صالح + إعادة ضبط اللون + ما يجب القيام به مع المقاطع المختلفة + تمكين مانِع الرُعَاة \"SponsorBlock\" + مانِع الرُعَاة هو نظام جماعي لتخطي الأجزاء المُمِلَّة في مقاطع اليوتيوب + تمكين SponsorBlock البديل + عند إغلاق خادم API التابع لــ SponsorBlock، قم بتبديل خادم API البديل إلى خادم API افتراضي + تمكين إضافة مقطع جديد + قم بتشغيل هذا الخيار لتمكين إضافة مقطع (قد يوجد مشاكل في رؤية الزر!) + تمكين التصويت + قم بتشغيل هذا الخيار لتمكين التصويت. + عام + تعديل تقديم او تأخير المقطع الجديد + أجزاء الثانية التي يمكنك تقديمها أو تأخيرها عند استخدام أزرار ضبط الوقت أثناء إضافة مقطع جديد + تغيير عنوان API + "العنوان الذي يستخدمه مانِع الرُعَاة لإجراء الاتصالات إلى الخادم. <b>لا تقم بتغيير هذا الخيار إلا إذا كنت تعرف ماذا تفعل.</b>" + تغيير رابط API البديل + "عنوان خادم بديل عند توقف خادم SponsorBlock. <b>لا تقم بتغيير هذا إلا إذا كنت تعرف ماذا تفعل.</b>" + الحد الأدنى لمدة المقطع + لن يتم تخطي المقاطع الأقصر من القيمة المحددة (بالثواني) أو عرضها في المشغل + تتبع عدد المقاطع التي تم تخطيها + يتيح هذا لنظام SponsorBlock Leaderboard معرفة مقدار الوقت الذي وفره المستخدمين، يقوم هذا المكون الإضافي بإعلام الخادم في كل مرة تتخطى فيها مقطعًا + إظهار إشعار عند تخطي المقطع تلقائيًا + انقر لمشاهدة مثال للإشعار + عرض الوقت بدون المقاطع + هذا الوقت يظهر بين القوسين بجوار الوقت الحالي. وهذا يعرض مجموع وقت الفيديو بدون المقاطع التي تم تخطيها. + معرف المستخدم الفريد الخاص بك + يجب أن يبقى هذا خاصًا. انه مثل كلمة المرور ولا ينبغي مشاركته مع أي شخص. إذا كان شخص ما يملك هذا، فيمكنه انتحال شخصيتك + الرجاء تثبيت MicroG + لم يتم العثور على MicroG + إعدادات الإشعارات + "1. يحتاج تسجيل جهاز Google و Google Cloud Messaging إلى تمكينهما للحصول على للإشعارات. +2. يحتاج ReVanced إلى أن يظهر كمسجل تحت المراسلة السحابية. +3. يجب عدم قطع الإتصال في المراسلة السحابية." + إعدادات MicroG + m + اختيار فئة المقطع + "المقطع يستمر من %02d:%02d إلى %02d:%02d (%d دقيقة %02d ثانية) هل هو جاهز للإرسال؟" + هل الأوقات صحيحة؟ + "لقد تم تعطيل هذه الفئة في الإعدادات، قم بتمكينها لتكون قادرة على الإرسال" + هل تود تعديل التوقيت لبداية أو نهاية المقطع؟ + الوقت المحدد غير صحيح + تم + تعديل توقيت المقطع يدويًا + النهاية + ضع علامة على موقعين في شريط الوقت أولًا + البداية + تعيين %02d:%02d:%04d كبداية أم نهاية لمقطع جديد؟ + الآن + الوقت الذي ينتهي عنده المقطع + تم تحديد نهاية المقطع + الوقت الذي يبدأ عنده المقطع + تم تحديد بداية المقطع + مقطع مانِع رُعَاة جديد + إعادة تعيين + الإعدادات المتعلقة بالإعلانات + إعدادات الإعلانات + يتم عرض بطاقات الألبوم من نتائج البحث + تم إخفاء بطاقات الألبوم من نتائج البحث + إخفاء بطاقات الألبوم + يتم عرض رفوف الأخبار العاجلة + تم إخفاء رفوف الأخبار العاجلة + إخفاء رف الأخبار العاجلة + يتم عرض الإعلانات الزرية + تم إخفاء الإعلانات الزرية + إخفاء الإعلانات الزرية + يتم عرض إرشادات القناة + تم إخفاء إرشادات القناة + إخفاء إرشادات القناة + يتم عرض ملخص للفصول تحت مقاطع الفيديو + تم إخفاء ملخص للفصول تحت مقاطع الفيديو + إخفاء ملخص الفصول تحت مقاطع الفيديو + يتم عرض إرشادات المجتمع + تم إخفاء إرشادات المجتمع + إخفاء إرشادات المجتمع + يتم عرض مشاركات المجتمع + تم إخفاء مشاركات المجتمع + إخفاء مشاركات المجتمع + يتم عرض شريط الإعلانات + تم إخفاء شريط الإعلانات + إخفاء شريط الإعلانات + تصفية المكونات حسب اسمها مفصولة بفاصلة + فلاتر مخصصة + يتم عرض صناديق الطوارئ + تم إخفاء صناديق الطوارئ + إخفاء صناديق الطوارئ + يتم عرض الإعلانات العامة + تم إخفاء الإعلانات بشكل عام + إخفاء الإعلانات العامة + يتم عرض رفوف الصور + تم إخفاء رفوف الصور + إخفاء رف الصور + يتم عرض لوحات المعلومات + تم إخفاء لوحات المعلومات + إخفاء لوحات المعلومات + يتم عرض الاستبيانات + تم إخفاء الاستبيانات + إخفاء الاستبيانات + يتم عرض أحدث المشاركات + تم إخفاء أحدث المشاركات + إخفاء آخر المشاركات + يتم عرض اللوحات الطبية + تم إخفاء اللوحات الطبية + إخفاء اللوحات الطبية + يتم عرض المنتجات ذات الصلة + تم إخفاء المنتجات ذات الصلة + إخفاء المنتجات ذات الصلة + يتم عرض رفوف الأفلام + تم إخفاء رفوف الأفلام + إخفاء رف الأفلام + يتم عرض البطاقات الرسمية من نتائج البحث + تم إخفاء البطاقات الرسمية من نتائج البحث + إخفاء البطاقات الرسمية + يتم عرض المحتوى المدفوع + تم إخفاء المحتوى المدفوع + إخفاء المحتوى المدفوع + يتم عرض بطاقات الرعاية الذاتية + تم إخفاء بطاقات الرعاية الذاتية + إخفاء بطاقات الرعاية الذاتية + يتم عرض الفواصل الرمادية + تم إخفاء الفواصل الرمادية + إخفاء الفاصل الرمادي + يتم عرض الاقتراحات + تم إخفاء الاقتراحات + إخفاء الاقتراحات + يتم عرض ردود الفعل المؤقتة + تم إخفاء ردود الفعل المؤقتة + إخفاء ردود الفعل المؤقتة + تم تعطيل عامل تصفية المستخدم + تم تمكين عامل تصفية المستخدم + تمكين عامل تصفية المستخدم + يتم عرض لافتة عرض المنتجات + تم إخفاء لافتة عرض المنتجات + إخفاء لافتة عرض المنتجات + يتم عرض لوحات البحث على الويب + تم إخفاء لوحات البحث على الويب + إخفاء لوحات بحث الويب + المدة الزمنية القصوى التي سيحاول المشغل تحميلها مسبقًا من الفيديو + الحد الأقصى لحجم التحميل المسبق + المدة التي يجب تحميلها مسبقًا من الفيديو لكي يبدأ أو يستأنف بعد إجراء المستخدم مثل تقديم الفيديو، (بالمللي ثانية) + +الافتراضي: 2500 + حجم بَدْء التحميل المسبق + مدة الوسائط التي يجب تخزينها مؤقتًا لاستئناف التشغيل بعد التحميل المسبق + حجم التحميل المسبق + الإعدادات المتعلقة بحجم التحميل المسبق + إعدادات التحميل المسبق + تحديد جودة الفيديو الافتراضية على شبكة الجوّال + جودة الفيديو الافتراضية على شبكة الجوَّال + تحديد جودة الفيديو الافتراضية على شبكة Wi-Fi + جودة الفيديو الافتراضية على شبكة Wi-Fi + تحديد سرعة الفيديو الافتراضية + سرعة الفيديو الافتراضية + غير مثبت. الرجاء تثبيته. + "اسم حُزْمَة تطبيق التنزيل مثل NewPipe's أو PowerTube's" + اسم حُزْمَة أداة التنزيل + الإعدادات الإفتراضية المتعلقة بالتنزيل + إعدادات التنزيل + يتم عرض واجهة شاشة النهاية + تم إخفاء واجهة شاشة النهاية + إخفاء واجهة شاشة النهاية + تم تمكين ردود الفعل اللمسية + تم تعطيل ردود الفعل اللمسية + تعطيل ردود الفعل اللمسية الخانقة + تم تمكين الاهتزاز عند الضغط على شريط تقدم الفيديو + تم تعطيل الاهتزاز عند الضغط على شريط تقدم الفيديو + تعطيل الاهتزاز عند الضغط على شريط تقدم الفيديو + تم تمكين الاهتزاز عند الضغط على الفصول + تم تعطيل الاهتزاز عند الضغط على الفصول + تعطيل الاهتزاز عند الضغط على الفصول + تعطيل الاهتزاز عند الضغط المطول + تعطيل الاهتزاز + تم تمكين الاهتزاز عند التكبير + تم تعطيل الاهتزاز عند التكبير + تعطيل الاهتزاز عند التكبير + تم نسخ الطابع الزمني إلى الحافظة + تم تعطيل التكرار التلقائي بشكل دائم + تم تمكين التكرار التلقائي بشكل دائم + التكرار التلقائي دائمًا + تعطيل إيماءات السحب عندما تكون عناصر تحكم المشغل مرئية + تمكين إيماءات السحب بشكل دائم سواءً عناصر تحكم المشغل مرئية أو غير مرئية + تمكين إيماءة السحب بشكل دائم + تم تعطيل سرعة التشغيل المخصصة + تم تمكين سرعة التشغيل المخصصة + تمكين سرعة الفيديو المخصصة + تم تعطيل المتصفح الخارجي + تم تمكين المتصفح الخارجي + تمكين المتصفح الخارجي + تم تعطيل سطوع HDR التلقائي + تم تمكين سطوع HDR التلقائي + تمكين سطوع HDR التلقائي + تم تعطيل التشغيل في الخلفية + تم تمكين التشغيل في الخلفية + تمكين التشغيل في الخلفية + سيتبع تصميم YouTube حالة حسابك في Google + خداع إصدار YouTube لفرض تفعيل التصميم القديم + تمكين التصميم القديم + يتم عرض المظهر الجديد لإعدادات جودة الفيديو + يتم عرض المظهر القديم لإعدادات جودة الفيديو + تمكين المظهر القديم لإعدادات جودة الفيديو + تُستخدم إعادة توجيه عنوان URL (youtube.com/redirect) عند فتح الروابط في أوصاف الفيديو + تجاوز إعادة توجيه عناوين URL (youtube.com/redirect) عند فتح الروابط في أوصاف الفيديو + تمكين فتح الروابط بشكل مباشر + تنشيط عناصر التحكم عن طريق السحب عند الضغط مباشرة + يتم تنشيط عناصر التحكم عن طريق السحب فقط بضغطة طويلة + الضغط للسحب + حِيَل نقاط لكل انش لاستخدام بعض تصميمات الجوال + تمكين تصميم الجوَّال + تم تعطيل النقر على شريط الوقت (شريط تقدم الفيديو) + لا يحتفظ بقيمة جودة الفيديو حتى عند تغيير جودة الفيديو + الاحتفاظ بقيمة جودة الفيديو كلما قمت بتغيير جودة الفيديو + تمكين حفظ جودة الفيديو + تم تمكين النقر على شريط الوقت (شريط تقدم الفيديو) + تمكين النقر على شريط الوقت + حتى إذا تم ضبط السطوع على 0 عن طريق السحب، فلن يتم تنشيط السطوع التلقائي + عندما يصل السطوع إلى 0 عن طريق السحب، يتم تنشيط السطوع التلقائي + تمكين السطوع التلقائي عن طريق السحب + تم تعطيل التحكم بمستوى السطوع عن طريق السحب + تم تمكين التحكم بمستوى السطوع عن طريق السحب + تمكين التحكم بالسطوع عن طريق السحب + تم تعطيل الاهتزاز عند الضغط على السحب + تم تمكين الاهتزاز عند الضغط على السحب + تمكين الاهتزاز عند الضغط على السحب + تم تعطيل التحكم بمستوى الصوت عن طريق السحب + تم تمكين التحكم بمستوى الصوت عن طريق السحب + تمكين التحكم بالصوت عن طريق السحب + تم تعطيل لوح المشغل المصَّغَّر + تم تمكين لوح المشغل المصَّغَّر + تمكين لوح المشغل المصَّغَّر + حِيَل نقاط لكل إنش لاستخدام بعض تصميمات الجهاز اللوحي + تمكين تصميم الجهاز اللوحي + تم تعطيل شريط البحث العريض + تم تمكين شريط البحث العريض + تمكين شريط البحث العريض + تعديلات تجريبية + الإبلاغ عن المشاكل أو ترك الاقتراحات هنا + مركز مشاكل ReVanced Extended + إعدادات ReVanced Extended + الإعدادات المتعلقة بــ Extended + إعدادات Extended + تم إيقاف تشغيل إصلاح مشكلات التحميل المسبق لتشغيل الفيديو + تم تشغيل إصلاح مشكلات التحميل المسبق لتشغيل الفيديو + إصلاح مشكلات التحميل المسبق لتشغيل الفيديو + تم تمكين التَّرْجَمَة عند فرض تشغيل مقطع فيديو مع التَّرْجَمَة + "تم تعطيل التَّرْجَمَة عند فرض تشغيل مقطع فيديو مع التَّرْجَمَة" + إخفاء التَّرْجَمَة التلقائية + يتم عرض لوحات المشغل المنبثقة تلقائيًا + تم إخفاء لوحات المشغل المنبثقة تلقائيًا + إخفاء لوحات المشغل المنبثقة تلقائيًا + يتم عرض زر التشغيل التلقائي + تم إخفاء زر التشغيل التلقائي + إخفاء زر التشغيل التلقائي + إخفاء مكون حاوية الزر + إخفاء مكون حاوية الزر + يتم عرض زر إنشاء مقطع + تم إخفاء زر إنشاء مقطع + إخفاء زر إنشاء مقطع + يتم عرض زر إنشاء مقطع قصير + تم إخفاء زر إنشاء مقطع قصير + إخفاء زر إنشاء مقطع قصير + يتم عرض زر \"لم يعجبني\" + تم إخفاء زر \"لم يعجبني\" + إخفاء زر عدم الإعجاب + يتم عرض زر التنزيل + تم إخفاء زر التنزيل + إخفاء زر التنزيل + يتم عرض زر \"أعجبني\" + تم إخفاء زر \"أعجبني\" + إخفاء زر الإعجاب + يتم عرض زر المحادثات المباشرة + تم إخفاء زر المحادثات المباشرة + إخفاء زر المحادثات المباشرة + يتم عرض زر قائمة التشغيل + تم إخفاء زر قائمة التشغيل + إخفاء زر قائمة التشغيل + يتم عرض زر الإبلاغ + تم إخفاء زر الإبلاغ + إخفاء زر الإبلاغ + يتم عرض زر مشاركة + تم إخفاء زر مشاركة + إخفاء زر مشاركة + يتم عرض زر شكرًا + تم إخفاء زر شكرًا + إخفاء زر شكرًا + يتم عرض زر التَرْجَمَة + تم إخفاء زر التَرْجَمَة + إخفاء زر التَرْجَمَة + يتم عرض زر البث + تم إخفاء زر البث + إخفاء زر البث + يتم عرض علامة الفيديو المائية + تم إخفاء علامة الفيديو المائية + إخفاء العلامة المائية للقناة + يخفي قسم التعليقات أو المكون + إخفاء عنصر التعليقات + يتم عرض قسم التعليقات + تم إخفاء قسم التعليقات + إخفاء قسم التعليقات + زر الإنشاء ظاهر بشكل افتراضي + تم إخفاء زر الإنشاء + إخفاء زر الإنشاء + يتم عرض مربع التمويل الجماعي + تم إخفاء مربع التمويل الجماعي + إخفاء مربع التمويل الجماعي + يتم عرض عنوان البريد الإلكتروني + تم إخفاء عنوان البريد الإلكتروني + إخفاء عنوان البريد الإلكتروني + يتم عرض بطاقات شاشة النهاية + تم إخفاء بطاقات شاشة النهاية + إخفاء بطاقات شاشة النهاية + يتم عرض حاوية زر ملء الشاشة + تم إخفاء حاوية زر ملء الشاشة + إخفاء حاوية زر ملء الشاشة + يتم عرض بطاقات المعلومات + تم إخفاء بطاقات المعلومات + إخفاء بطاقات المعلومات + يتم عرض قائمة الوضع المحيط + تم إخفاء قائمة الوضع المحيط + إخفاء قائمة الوضع المحيط + يتم عرض قائمة مسار الصوت + تم إخفاء قائمة مسار الصوت + إخفاء قائمة مسار الصوت + يتم عرض قائمة التَرْجَمَة + تم إخفاء قائمة التَرْجَمَة + إخفاء قائمة التَرْجَمَة + يتم عرض قائمة المساعدة & ردود الفعل + تم إخفاء قائمة المساعدة & ردود الفعل + إخفاء قائمة المساعدة & ردود الفعل + يتم عرض قائمة التحكم في الإستماع + تم إخفاء قائمة التحكم في الإستماع + إخفاء قائمة عناصر التحكم في الإستماع + يتم عرض الاستماع مع قائمة موسيقى اليوتيوب + تم إخفاء الاستماع مع قائمة موسيقى اليوتيوب + إخفاء الاستماع مع قائمة موسيقى اليوتيوب + يتم عرض قائمة تكرار الفيديو + تم إخفاء قائمة تكرار الفيديو + إخفاء قائمة تكرار الفيديو + يتم عرض قائمة المزيد من المعلومات + تم إخفاء قائمة المزيد من المعلومات + إخفاء قائمة المزيد المعلومات + يتم عرض قائمة الإبلاغ + تم إخفاء قائمة الإبلاغ + إخفاء قائمة الإبلاغ + يتم عرض قائمة إحصاءات تقنية + تم إخفاء قائمة إحصاءات تقنية + إخفاء قائمة إحصاءات تقنية + يتم عرض قائمة المشاهدة بوضع VR + تم إخفاء قائمة المشاهدة بوضع VR + إخفاء قائمة المشاهدة بوضع VR + يتم عرض قائمة تشغيل التشكيلة + تم إخفاء قائمة تشغيل التشكيلة + إخفاء قائمة تشغيل التشكيلة + يتم عرض تعليق المعاينة + تم إخفاء تعليق المعاينة + إخفاء تعليق المعاينة + يتم عرض زر Shorts + تم إخفاء زر Shorts + إخفاء زر Shorts + يخفي قسم فيديوهات Shorts أو عنصر مشغل Shorts + إخفاء مكون Shorts + يتم عرض زر تعليقات فيديوهات Shorts + تم إخفاء زر تعليقات فيديوهات Shorts + إخفاء زر تعليقات فيديوهات Shorts + إخفاء مكون مشغل Shorts + يتم عرض زر ريمكس في مشغل Shorts + تم إخفاء زر ريمكس في مشغل Shorts + إخفاء زر ريمكس في مشغل فيديوهات Shorts + يتم عرض زر الاشتراكات في فيديوهات Short + تم إخفاء زر الاشتراكات في فيديوهات Short + إخفاء زر الاشتراكات في فيديوهات Short + يتم عرض زر شكرًا في مشغل Shorts + تم إخفاء زر شكرًا في مشغل Shorts + إخفاء زر شكرًا في مشغل Shorts + يتم عرض رفوف الفيديوهات القصيرة (Shorts) + تم إخفاء رفوف الفيديوهات القصيرة (Shorts) + إخفاء رف الفيديوهات القصيرة (Shorts) + تم تعطيل مشغل Shorts عند بَدْء تشغيل التطبيق + تم تمكين مشغل Shorts عند بَدْء تشغيل التطبيق + مشغل Shorts عند بَدْء تشغيل التطبيق + يتم عرض رفوف القصص + تم إخفاء رفوف القصص + إخفاء رف القصص + يتم عرض الإجراءات المقترحة + تم إخفاء الإجراءات المقترحة + إخفاء الإجراءات المقترحة + يتم عرض الوقت وشريط تقدم الفيديو + تم إخفاء الوقت وشريط تقدم الفيديو + إخفاء الوقت وشريط تقدم الفيديو + إعدادات تصميم المشغل السفلي + إعدادات تصميم القائمة المنبثقة + إعدادات تصميم ملء الشاشة + إعدادات التصميم العامة + إعدادات تصميم المشغل + إعدادات تصميم شريط تقدم الفيديو + الإعدادات المتعلقة بالتصميم + إعدادات التصميم + إعدادات متنوعة ذات صلة + إعدادات متنوعة + أخرى + تم إخفاء زر التكرار التلقائي + يتم عرض زر التكرار التلقائي + عرض زر التكرار التلقائي + تم إخفاء زر نسخ الرابط + يتم عرض زر نسخ الرابط + عرض زر نسخ الرابط + تم إخفاء زر نسخ الرابط مع الوقت + يتم عرض زر نسخ الرابط مع الوقت + عرض زر نسخ الرابط مع الوقت + تم إخفاء زر التنزيل + يتم عرض زر التنزيل + عرض زر التنزيل + الإعدادات المتعلقة بزر مشغل الفيديو + إعدادت زر المشغل + تم إخفاء زر القائمة البيضاء + يتم عرض زر القائمة البيضاء + عرض زر القائمة البيضاء + العنوان الحالي: الافتراضي + العنوان الحالي: Premium Header + Premium Header + معلومات عن التعديلات المطبقة + معلومات التعديلات + إخفاء المكون الخاص بلوحة إعدادات المشغل المنبثقة + المكون الخاص بلوحة إعدادات المشغل المنبثقة + "نظرًا لأن هذه المِيزة لا تزال تجريبية، فقد تكون هناك مشكلات أخرى غير معروفة. +هل أنت متأكد أنك تريد الاستمرار بالرغم من ذلك؟" + "يخدع إصدار YouTube إلى الإصدار 17.28.35 لتحميل التصميم القديم + +في إعدادات التطبيق، قد يتم تمييز إصدار YouTube كـ v17.28.35" + "حيل نقطة في البوصة لتغيير بعض التصميمات لتصميمات الجوال. + +إذا قمت بتمكين هذا الإعداد، فستتوفر الميزات التالية: +- مشاركات المجتمع +- إخفاء قائمة تشغيل التشكيلة" + "إصلاح مشاكل التحميل المسبق لتشغيل الفيديو في بعض المناطق. + +إذا قمت بتمكين هذا الإعداد، فقد تحدث المشكلة التالية: +- عند تشغيل مقطع فيديو في قائمة التشغيل، قد لا يتم حل المشكلة" + "حيل نقطة في البوصة لتغيير بعض التصميمات لتصميمات الجهاز اللوحي. + +إذا قمت بتمكين هذا الإعداد، فستتوفر الميزات التالية: +- الوضع المحيط +- مشاركات المجتمع" + يتم توفير بيانات عدم إعجاب مقاطع يوتيوب بواسطة True RYD Worker API. اضغط هنا لمعرفة المزيد. + true-ryd.cane.workers.dev + تم تعطيل API البديل + تم تمكين API البديل + تمكين API البديل + "تستخدم True RYD Worker API عدد إبداءات عدم الإعجاب المعروضة في YouTube API Endpoint. + +قم بتمكين هذا الخيار فقط لأولئك الذين يواجهون +مشاكل أثناء استخدام واجهة برمجة تطبيقات RYD الافتراضية. + + هل ترغب في الاستمرار؟" + True RYD Worker + يتم توفير بيانات عدم إعجاب مقاطع يوتيوب بواسطة the Return YouTube Dislike API. اضغط هنا لمعرفة المزيد. + ReturnYouTubeDislike.com + يظهر عدد عدم الإعجاب كـ رَقَم + يظهر عدد عدم الإعجاب كـ نسبة مئوية + عدم الإعجاب كـ نسبة مئوية + لا يتم عرض عدم الإعجاب + يتم عرض عدم الإعجاب + إرجاع YouTube Dislike + عدم الإعجاب غير متاح (تم الوصول إلى حد API العميل) + فشل ReturnYouTubeDislike في تأكيد المستخدم الجديد + فشل ReturnYouTubeDislike في تأكيد التصويت + عدم الإعجاب غير متوفر مؤقتًا (انتهت مهلة API) + فشل ReturnYouTubeDislike في التسجيل كمستخدم جديد + فشل ReturnYouTubeDislike في إرسال التصويت + الإعدادات المتعلقة بإرجاع عدد عدم الإعجاب + إرجاع YouTube Dislike + (ReVanced) إعدادات + الإعدادات المتعلقة بالتفاعلات + إعدادات التفاعل + الحد الأدنى من الحجم قبل اكتشاف السحب + مقدار حد السحب + قيمة شفافية خلفية واجهة السحب (0-255) + شفافية خلفية واجهة السحب + حجم النص على واجهة السحب + حجم نص واجهة السحب + كم من الوقت تظهر واجهة السحب بعد التغيير (بالملي ثانية) + مهلة واجهة السحب + الأداة المستخدمة + يتم عرض إعلانات الفيديو + تم إخفاء إعلانات الفيديو + إخفاء إعلانات الفيديو + فشل في ضبط الجودة + لا يوجد اتصال بالإنترنت + تغيير جودة بيانات الجوال الافتراضية إلى: + فشل في تغيير جودة بيانات الجوال الافتراضية + تغيير جودة Wi-Fi الافتراضية إلى: + فشل في تغيير جودة Wi-Fi الافتراضية + الإعدادات المتعلقة بالفيديو + إعدادات الفيديو + فشل إضافة القناة %s إلى القائمة البيضاء %s + تمت إضافة القناة %s إلى القائمة البيضاء %s + إعلانات الفيديو + الإعلانات + اسم القناة + لا توجد قنوات مدرجة في القائمة البيضاء + لم يتم إضافتها إلى القائمة البيضاء + تمت الإضافة إلى القائمة البيضاء + قائمة القنوات البيضاء + فشل في استرجاع تفاصيل القناة، الرمز المتلقى%d + إعادة التشغيل لتطبيق إعدادات قائمة القناة البيضاء + فشل إزالة القناة %s من القائمة البيضاء %s + تمت إزالة القناة %s من القائمة البيضاء %s + التحقق أو إزالة قائمة القنوات المضافة إلى القائمة البيضاء + إعدادات القائمة البيضاء + سرعة الفيديو + السرعة + SponsorBlock-مانِع الرُعَاة + SB + خادم SponsorBlock لا يستجيب! + تمت قراءتها + "من المستحسن قراءة الإرشادات لمانع الرعاة قبل تقديم أي مقطع" + اعرضها لي + توجد إرشادات + الإرشادات تحتوي على نصائح حول تقديم المقاطع + عرض الإرشادات + SponsorBlock إعدادات مانِع الرُعَاة + SponsorBlock الإعدادات المتعلقة بــ + تم التبديل بنجاح. أعد تحميل الفيديو + تبديل خادم API البديل إلى خادم API الرئيسي.. + الخاتمة/تترات النهاية + تتر النهاية أو عندما تظهر بطاقات النهاية، نهايات غير منطوقة + خارج الموضوع/النكات + تم إضافة مشاهد ملتقطة خارج الموضوع أو الفكاهة التي ليست مطلوبة لفهم المحتوى الرئيسي للفيديو. وينبغي ألا يشمل ذلك الأجزاء التي تقدم تفاصيل عن السياق أو الخلفية + المقدمة/فاصل + فاصل زمني بدون محتوى فعلي. يمكن أن يكون توقف مؤقت، إطارًا ثابتاً، تكرار المقدمة + الموسيقى: مقطع بدون موسيقى + فقط للاستخدام في مقاطع الفيديو الموسيقية. يتخطى أجزاء من الفيديو ليست في عمليات المزج الرسمية + معاينة/موجز + "ملخص للحلقات السابقة، أو معاينة ما سيعرض لاحقًا في الفيديو الحالي أو مقاطع الفيديو المستقبلية في نفس السلسلة. يجب ألا توفر المقاطع معلومات إضافية." + ترويج شخصي/غير مدفوع الأجر + شبيهة بـ \"الراعي\" باستثناء ما يتعلق بالإعلانات غير المدفوعة الأجر أو الذاتية. ويشمل ذلك أقسام عن السلع أو التبرعات أو المعلومات المتعلقة بمن تعاونوا مع ناشر المحتوى + الراعي + الترويج المدفوع الأجر، والإحالات المدفوعة الأجر والإعلانات المباشرة + تذكير بالتفاعل (الاشتراك في القناة) + عندما يكون هناك تذكير قصير للإعجاب بالمقطع أو الاشتراك بالقناة أو المتابعة أو التفاعل معهم على أي منصة مجانية أو مدفوعة + فشل تصدير الإعدادات + إستيراد/تصدير الإعدادات + يتم تخزين جميع إعداداتك بتنسيق JSON المتوافق مع المكون الإضافي لسطح المكتب. يتضمن هذا معرف المستخدم الفريد الخاص بك، لِذا فكر مرتين قبل مشاركته. + فشل استيراد الإعدادات + تم استيراد الإعدادات بنجاح + التخطي تلقائيًا + التخطي تلقائيًا مرة واحدة + "لا تفعل أي شيء" + عرض زر التخطي + تخطي المقطع + تم تخطي الخاتمة + تم تخطي مقطع غير ذي صلة + تم تخطي المقدمة + تم تخطي جزء غير موسيقي + تم تخطي النظرة العامة + تم تخطي مقطع الراعي + تم تخطي الترويج الشخصي + تم تخطي الراعي + تم تخطي التذكير بالتفاعل + تم تخطي المقطع الغير المرسل + إحصائيات + جارٍ التحميل... + "لقد قمت بحفظ الناس من <b>%s</b> مقطع." + "هذا يساوي <b>%s</b> من حياتهم. انقر لرؤية لوحة المتصدرين" + تم تعطيل مانِع الرُعَاة + "لقد قمت بتخطي <b>%s</b> مقطع." + "هذا يساوي <b>%s</b>." + المقاطع المرسلة: <b>%s</b> + اسم المستخدم الخاص بك: <b>%s</b> + انقر لتغيير إسم المستخدم الخاص بك + غير قادر على تغيير اسم المستخدم: الحالة: %d %s + تم تغيير اسم المستخدم بنجاح + "لا يمكن إرسال هذا المقطع.\nموجود بالفعل" + "لا يمكن إرسال المقطع.\n\n%s" + "لا يمكن إرسال المقطع.\n جارٍ الحد من معدل إرسالك (عدد كبير جدا من نفس المستخدم أو IP)" + لا يمكن إرسال المقطع: %s + غير قادر على إرسال المقاطع: الحالة: %d %s + جارٍ إرسال المقطع… + تم إرسال المقطع بنجاح + انقر للتخطي + تغيير التصنيف + اعتراض + "لا يمكن التصويت على المقطع.\n\n%s" + "لا يمكن التصويت على المقطع.\n جارٍ الحد من معدل إرسالك (عدد كبير جدا من نفس المستخدم أو IP)" + غير قادر على التصويت للمقطع: الحالة: %d %s + لا توجد مقاطع للتصويت عليها + جارٍ التصويت للمقطع… + تم التصويت بنجاح + تأييد + diff --git a/src/main/resources/youtube/translations/az-rAZ/strings.xml b/src/main/resources/youtube/translations/az-rAZ/strings.xml new file mode 100644 index 000000000..bada63b82 --- /dev/null +++ b/src/main/resources/youtube/translations/az-rAZ/strings.xml @@ -0,0 +1,90 @@ + + + Haqqında + Bu proqram SponsorBlock-dan API istifadə edir + Ətraflı öyrənmək üçün toxunun və digər platformalar üçün endirmələrə baxın: sponsor.ajay.app + İnteqrasiya JakubWeg tərəfindən hazırlanmışdır + Video pleyer üçün əlçatanlıq nəzarətləri aktiv edilsin? + Əlçatımlılıq xidməti aktiv olduğu üçün nəzarətləriniz dəyişdirilib. + API URL dəyişdirildi + Təqdim olunan API URL-i etibarsızdır + API URL sıfırlaması + API MIRROR URL dəyişdirildi + Təqdim olunan API MIRROR URL etibarsızdır + API MIRROR URL sıfırlaması + Dəyişən rənglər axtarırsınız? + "İndi yuxarıdakı üzərinə klikləməklə kateqoriyanın rəngini dəyişə bilərsiniz." + Rəng dəyişdi + Yanlış hex kodu + Rəng sıfırlaması + Fərqli seqmentlərlə nə etmək lazımdır + SponsorBlock-u aktivləşdirin + SponsorBlock, YouTube videolarında zəhlətökən hissələri atlamaq üçün izdihamlı bir sistemdir + SponsorBlock Mirror-u aktivləşdirin + SponsorBlock API serveri ləğv edildikdə, güzgü API serverini defolt API serverinə keçirin + Yeni seqment əlavəsini aktivləşdirin + Eksperimental seqment əlavəsini aktiv etmək üçün bunu aktiv edin (düymənin görünmə problemi var) + Səsverməyə icazə verin + Səsverməni aktivləşdirmək üçün bunu yandırın. + Ümumi + Yeni seqment addımının tənzimlənməsi + Bu, yeni seqment əlavə edərkən vaxt tənzimləmə düymələrindən istifadə edərkən hərəkət edə biləcəyiniz millisaniyələrin sayıdır + API URL-ni dəyişdirin + "SponsorBlock serverə zəng etmək üçün istifadə etdiyi ünvan. Nə etdiyinizi bilmədən bunu dəyişməyin. " + API Güzgü URL-ni dəyişdirin + "SponsorBlock serveri ləğv edildikdə keçid üçün güzgü server ünvanı. Nə etdiyinizi bilmədən bunu dəyişməyin." + Minimum seqment müddəti + Təyin edilmiş dəyərdən (saniyələrlə) qısa olan seqmentlər qaçırılmayacaq və ya pleyerdə göstərilməyəcək + Sayı izləməni keçin + Bu, SponsorBlock liderlər lövhəsi sisteminə insanların nə qədər vaxta qənaət etdiyini bilmək imkanı verir. Seqmenti hər dəfə atladığınız zaman artırma serverə mesaj göndərir + Seqmenti avtomatik keçərkən tost göstərin + Tost nümunəsinə baxmaq üçün klikləyin + Seqmentlər olmadan vaxtı göstərin + Bu vaxt cari vaxtın yanında mötərizədə göstərilir. Bu, hər hansı bir seqment çıxılmaqla ümumi video müddətini göstərir. + Şəxsi istifadəçi identifikatorunuz + Bu gizli saxlanılmalıdır. Bu parol kimidir və heç kimlə paylaşılmamalıdır. Əgər kimsə buna sahibdirsə, o, sizi təqlid edə bilər + Zəhmət olmasa MicroG-ni quraşdırın + MicroG tapılmadı + MicroG Bildiriş parametrləri + "1. Bildirişlər üçün Google cihazının qeydiyyatı və Bulud Mesajlaşması aktivləşdirilməlidir. +2. ReVanced Cloud Messaging altında qeydiyyatdan keçdiyi kimi göstərilməlidir. +3. Bulud Mesajlaşmasında cari vəziyyət qoşulu olmalıdır." + MicroG parametrləri + dəqiqə + Seqment kateqoriyasını seçin + "Seqment %02d:%02d ilə %02d:%02d arasında davam edir (%d dəqiqə %02d saniyə) +Təqdim etməyə hazırdır?" + Vaxtlar düzgündür? + "Siz parametrlərdə bu kateqoriyanı deaktiv etmisiniz, onu təqdim etmək üçün aktivləşdirin" + Seqmentin başlanğıcı və ya sonu üçün vaxtı redaktə etmək istəyirsiniz? + Yanlış vaxt verilmişdir + Bitdi + Seqmentin vaxtını əl ilə redaktə edin + son + Əvvəlcə vaxt çubuğunda iki yeri qeyd edin + başlanğıc + %02d:%02d:%04d yeni seqmentin başlanğıcı və ya sonu kimi təyin edilsin? + indi + Seqmentin bitmə vaxtı + Seqment setinin sonu + Seqmentin başladığı vaxt + Seqment dəstinin başlanğıcı + Yeni SponsorBlock seqmenti + Sıfırla + Albom kartları axtarış nəticələrində göstərilir + Albom kartları axtariş nəticələrində göstərilmir + Albom kartlarını gizlət + Son dəqiqə xəbərlər paneli gizli deyil + Son dəqiqə xəbərlər paneli gizlidi + Son dəqiqə xəbərlər panelini gizlət + Basılan reklamlar gizli deyil + Basılan reklamlar gizlidi + Basılan reklamlari gizlət + Kanal təlimatlarını gizli deyil + Kanal təlimatlarını gizlidi + Kanal təlimatlarını gizlət + İcma Qaydaları Təlimatı gizli deyil + İcma Qaydaları Təlimatı gizlidi + İcma Qaydalar Təlimatını gizlət + İcma Qaydalar Təlimatı gizli deyil + diff --git a/src/main/resources/youtube/translations/be-rBY/strings.xml b/src/main/resources/youtube/translations/be-rBY/strings.xml new file mode 100644 index 000000000..192d015b0 --- /dev/null +++ b/src/main/resources/youtube/translations/be-rBY/strings.xml @@ -0,0 +1,121 @@ + + + Пра нас + Гэта праграма выкарыстоўвае API ад SponsorBlock + Націсніце, каб даведацца больш і паглядзець спампоўкі для іншых платформ на: sponsor.ajay.app + Аўтар інтэграцыі - JakubWeg + Уключыць спецыяльныя магчымасці для відэаплэера? + Вашы элементы кіравання зменены, таму што служба спецыяльных магчымасцяў уключана. + URL API змяніўся + Дадзены URL API памылковы + Скінуць URL API + URL-адрас API MIRROR зменены + Прадстаўлены URL-адрас API MIRROR несапраўдны + Скід URL-адраса API MIRROR + Вы жадаеце змяніць каляровую тэму? + "Зараз вы можаце змяніць колер катэгорыі, націснуўшы на яго вышэй." + Колер зменены + Памылковы hex код + Скід колеру + Што рабіць з рознымі сегментамі + Уключыць SponsorBlock + SponsorBlock – краўдсорсінгавая сістэма для пропуску надакучлівых частак відэа YouTube + Уключыць SponsorBlock Mirror + Калі сервер API SponsorBlock адключаецца, пераключыце люстраны сервер API на сервер API па змаўчанні + Уключыць дадаванне новага сегмента + Уключыце, каб актываваць эксперыментальнае дабаўленне сегментаў (маюцца праблемы з адлюстраваннем кнопак) + Уключыць галасаванне + Пераключыце гэта, каб уключыць галасаванне. + Асноўныя + Наладжванне кроку новага сегмента + Гэта колькасць мілісекунд, якія вы можаце прапусціць, калі выкарыстоўваеце кнопкі рэгулявання часу падчас дадання новага сегмента + Змяніць API URL адраса + "Адрас SponsorBlock выкарыстоўвае для зварота на сервер. <b>Не змяняйце гэта, калі вы не ведаеце, што робіце.</b>" + Змяніць URL-адрас люстэрка API + "Люстраны адрас сервера, калі сервер SponsorBlock не даступны. <b>Не мяняйце, калі не ведаеце, што робіце</b>" + Мінімальная працягласць сегмента + Сегменты, меншыя за ўстаноўленае значэнне (у секундах), не будуць прапускацца і не паказвацца ў плэеры + Падлік колькасці пропускаў + Гэта пазваляе SponsorBlock падлічваць зэканомлены людзьмі час. Пашырэнне адпраўляе паведамленне на сервер кожны раз, калі вы прапускаеце сегмент + Паказваць паведамленне калі сегмент аўтаматычна прапушчаны + Націсніце, каб паглядзець прыклад такога паведамлення + Паказваць час без сегментаў + Гэты час будзе у скобках побач з бягучым часам. Ён паказвае агульную працлегласць відэа мінус сегменты. + Ваш унікальны карыстальніцкі id + Гэта патрэбна трымаць у сакрэце. Гэта як пароль, і яго нельга нікому перадаваць. Калі ў кагосьці ёсць гэта, яны могуць выдаваць сябе за вас + Калі ласка, усталюйце MicroG + MicroG не знойдзены + Параметры апавяшчэнняў + "1. Рэгістрацыя прылады ў Google і Cloud Messanging павінны быць уключаны для адпраўлення паведамленняў. +2. ReVanced павінен адлюстроўвацца як зарэгістраваны ў Cloud Messanging. +3. Стан у Cloud Messanging павінен быць \"Падлучана\"." + Налады MicroG + хвіліны + Выберыце катэгорыю сегмента + "Сегмент доўжыцца ад %02d:%02d да %02d:%02d (%d хвілін %02d секунд)\nЦі гатовы ён да адпраўкі?" + Час пачатка і канца сегмента верны? + "Вы адключылі гэту катэгорыю ў наладах, уключыце яе для даслання сегмента" + Вы хочаце змяніць час пачатку або канца сегмента? + Час указаны некарэктна + Гатова + Змяніць час сегмента ўручную + канец + Па-пераше, пазначце спачатку два месца на шкале часу + пачаць + Пазначыць %02d:%02d:%04d як пачатак і канец новага сегмента? + зараз + Час канца сегмента + Канец сегмента пазначан + Час пачатку сегмента + Пачатак сегмента пазначана + Новы SponsorBlock сегмент + Скінуць + Налады адлюстравання рэкламы + Налады рэкламы + Карткі альбомаў паказваюцца з вынікаў пошуку + Карткі альбомаў схаваны ў выніках пошуку + Схаваць карткі альбомаў + Панэль апошніх навін адлюстравана + Панэль апошніх навін схавана + Схаваць панэль апошніх навін + Клікабельная рэклама на галоўнай старонцы адлюстравана + Клікабельная рэклама на галоўнай старонцы схавана + Схаваць клікабельную рэкламу + Правілы канала адлюстраваны + Правілы канала схаваны + Схаваць рэкамендацыі канала + Тызер раздзела пад відэа адлюстраваны + Тызер раздзела пад відэа схаваны + Схаваць цізер раздзела пад відэа + Паказваць правілы супольнасці + Правілы супольнасці схаваныя + Схаваць правілы супольнасці + Паказваюцца паведамленні ў супольнасці + Паведамленні ў супольнасці схаваны + Схаваць паведамленні ў супольнасці + Паказваюцца кампактныя банеры + Кампактныя банеры схаваныя + Схаваць кампактныя банеры + Фільтраваць кампаненты па іх назве, падзяляючы іх коскамі + Карыстальніцкі фільтр + Паказваць аварыйныя скрыні + Схаваць аварыйныя скрыні + Схаваць аварыйныя скрыні + Паказваць рэкламу агульнага фармату + Рэклама агульнага фармату схавана + Схаваць рэкламу агульнага фармату + Публікацыі з выявамі адлюстраваны + Публікацыі з выявамі схаваныя + Схаваць публікацыі з выявамі + Паказваць інфармацыйныя панэлі + Інфармацыйныя панэлі схаваны + Схаваць інфармацыйныя панэлі + Публікацыі з фільмамі схаваныя + Схаваць публікацыі з фільмамі + Афіцыйныя карткі паказваюцца з вынікаў пошуку + Афіцыйныя карткі схаваны з вынікаў пошуку + Схаваць афіцыйныя карты + Банеры платнага кантэнту адлюстраваны + Банеры платнага кантэнту схаваны + Схаваць банеры платнага кантэнту + diff --git a/src/main/resources/youtube/translations/de-rDE/strings.xml b/src/main/resources/youtube/translations/de-rDE/strings.xml new file mode 100644 index 000000000..199f619a7 --- /dev/null +++ b/src/main/resources/youtube/translations/de-rDE/strings.xml @@ -0,0 +1,422 @@ + + + Über + Diese App verwendet API vom SponsorBlock + Tippen, um mehr zu erfahren und Downloads für andere Plattformen anzuzeigen: sponsor.ajay.app + Integration erstellt von JakubWeg + Bedienungshilfen für den Video-Player aktivieren? + Deine Steuerelemente wurden geändert, weil ein Barrierefreiheitdienst aktiviert ist. + API URL wurde geändert + Die angegebene API URL ist ungültig + API URL reset + API MIRROR URL wurde geändert + Die angegebene API URL ist ungültig + API MIRROR URL wurde geändert + Möchtest du die Farben ändern? + "Sie können nun die Farbe einer Kategorie ändern, indem Sie oben auf sie klicken." + Farbe wurde geändert + Ungültiger Hex-Code + Farben zurücksetzen + Was soll mit verschiedenen Segmenten gemacht werden + SponsorBlock aktivieren + SponsorBlock ist ein auf Crowdsourcing basierendes System zum Überspringen von störenden Abschnitten in YouTube-Videos + SponsorBlock aktivieren + Wenn der SponsorBlock API-Server heruntergefahren wird, wechseln Sie den Mirror-API-Server auf den Standard-API-Server + Hinzufügen neuer Segmente erlauben + Aktivieren Sie diese Option, um das Hinzufügen von experimentellen Segmenten zu ermöglichen (es gibt Probleme mit der Sichtbarkeit von Buttons) + Abstimmung aktivieren + Schalten Sie dies ein, um die Abstimmung zu aktivieren. + Allgemein + Neuen Segmentschritt anpassen + Die Anzahl der Millisekunden, die bei der Segmenterstellung per Zeitanpassungsschaltfläche bewegt werden können + API URL ändern + "Die Adresse über die SponsorBlock den Server anfragt. <b> Ändern Sie dies nicht, es sei denn, Sie wissen, was Sie tun. </b>" + API Mirror URL ändern + "Mirror der Serveradresse, zu der gewechselt wird, wenn der SponsorBlock Server heruntergefahren wird. <b>Ändern Sie dies nicht, es sei denn, Sie wissen was Sie tun.</b>" + Mindestdauer der Segmente + Videosegmente, die kürzer als der festgelegte Wert (in Sekunden) sind, werden nicht übersprungen oder im Player angezeigt + Zählertracking überspringen + Hierdurch weiß das Leaderboard-System von SponsorBlock, wie viel Zeit die Nutzer gespart haben. Die Erweiterung sendet jedes Mal eine Nachricht an den Server, wenn du ein Segment überspringst + Einen Toast beim automatischen Überspringen des Segments anzeigen + Klicke, um einen Beispieltoast zu sehen + Zeit ohne Segmente anzeigen + Die Zeitangabe erscheint in Klammern neben der aktuellen Videozeit. Sie zeigt die gesamte Videodauer abzüglich jedweder Segmente. + Ihre private Benutzer-ID + Dies sollte vertraulich behandelt werden. Dies ist wie ein Passwort und sollte mit niemandem geteilt werden. Wenn jemand dies hat, kann er sich für dich ausgeben + Bitte MicroG installieren + MicroG wurde nicht gefunden + Benachrichtigungseinstellungen + "1. Registrierung von Google-Geräten und Google Cloud Messaging müssen aktiviert sein, damit Benachrichtigungen funktionieren. +2. ReVanced muss unter Cloud Messaging als registriert angezeigt werden. +3. Der aktueller Google Cloud Messaging-Status darf nicht getrennt sein." + MicroG Einstellungen + Minuten + Wähle eine Segment-Kategorie aus + "Der Abschnitt dauert von %02d:%02d bis %02d:%02d (%d Minuten und %02d Sekunden). +Ist es fertig zum Einreichen?" + Sind die Zeiten korrekt? + "Du hast diese Kategorie in den Einstellungen deaktiviert, aktiviere sie um einreichen zu können" + Willst du die Start- oder Endzeiten für den Abschnitt bearbeiten? + Ungültige angegebene Zeit + Fertig + Zeiten des Abschnitts manuell bearbeiten + Ende + Markiere erst zwei Positionen auf der Zeitleiste + Start + Soll %02d:%02d:%04d als Start oder Ende für den neuen Abschnitt gesetzt werden? + Jetzt + Zeit, bei der der Abschnitt endet + Ende des Abschnitts + Start des Abschnitts + Start des Abschnitts gesetzt + Neuer SponsorBlock Abschnitt + Zurücksetzen + Werbebezogene Einstellungen + Werbung \"ADS\" Einstellungen + Albumkarten werden aus den Suchergebnissen angezeigt + Albumkarten werden nicht aus den Suchergebnissen gezeigt + Verstecke Albumkarten + Schlagzeilen Abschnitte werden angezeigt + Schlagzeilen Abschnitte sind ausgeblendet + Schlagzeilen Abschnitt verbergen + Klickbare Werbung wird angezeigt + Klickbare Werbung ist versteckt + Verstecke Klickbare Werbung + Kanalrichtlinien werden angezeigt + Kanalrichtlinien sind versteckt + Verstecke Kanalrichtlinien + Teaser des Kapitels werden angezeigt + Teaser des Kapitels sind versteckt + VErstecke Kapitel Teaser unter Videos + Communityrichtlinien sind aktiviert + Communityrichtlinien sind versteckt + Verstecke Gemeinschaftsrichtlinien + Community-Beiträge werden angezeigt + Community-Beiträge sind versteckt + Verstecke Community-Beiträge + Kompakte Banner werden angezeigt + Kompakte Banner sind versteckt + Entferne kompakte Werbe-Banner + Filtere Komponenten nach ihrem Namen getrennt durch Komma + Individuelle Filter + Notfall-Boxen werden angezeigt + Notfall-Boxen sind versteckt + Entferne Notfallboxen + Allgemeine Werbung wird angezeigt + Allgemeine Werbung ist versteckt + Allgemeine Werbung ausblenden + Shorts werden angezeigt + Shorts sind versteckt + Infokarten werden angezeigt + Infokarten werden ausgeblendet + Info-Panels ausblenden + Feed-Umfragen werden angezeigt + Feed-Umfragen sind versteckt + Entferne Umfragen + Neueste Beiträge werden angezeigt + Neueste Beiträge sind versteckt + Entferne neueste Beiträge + Medical Infokarten werden angezeigt + Medical Panels sind versteckt + Verstecke Medical Infokarten + Warenbanner werden angezeigt + Warenbanner sind versteckt + Werbebanner verstcken + Offizielle Karten werden aus den Suchergebnissen angezeigt + Offizielle Karten sind aus Suchergebnissen ausgeblendet + Verstecke Offizielle Karten + Bezahlter Inhalt wird angezeigt + Bezahlter Inhalt ist ausgeblendet + Verstecke bezahlte Inhalte + Selbstgesponserte Karten werden angezeigt + Selbstgesponserte Karten sind versteckt + Verstecke selbstgesponserte Karten + Graue Trennzeichen werden angezeigt + Graue Trennzeichen sind ausgeblendet + Verstecke graue Trennzeichen + Vorschläge werden angezeigt + Vorschläge sind versteckt + Entferne generelle Vorschläge + Zeitgesteuerte Reaktionen werden angezeigt + Zeitgesteuerte Reaktionen sind versteckt + Reaktionen verbergen + Bildschirmfilter ist deaktiviert. + Bildschirmfilter ist aktiviert + Bildschirmfilter aktivieren + Produkt-Banner anzeigen + Produkt-Banner anzeigen ist ausgeblendet + Verstecke Produkt-Banner + Websuchfenster werden angezeigt + Websuche-Panels sind versteckt + Web-Suchfenster ausblenden + Die maximale Dauer der Medien, die der Player zu puffern versucht + Maximale Puffergröße + Die Länge der Medien, die gepuffert werden muss, um die Wiedergabe zu starten oder fortzuführen + Startpuffergröße für Wiedergabe + Die Dauer von Medien, die gepuffert werden müssen, um nach einem Rebuffer wiederzugeben + Rebuffer-Größe + Einstellungen für Video-Puffer + Video-Puffereinstellungen + Wähle die Standard-Videoauflösung im Mobilfunknetz + Standard Videoqualität im Mobilfunk + Wähle die Standard-Videoauflösung im Wi-Fi-Netzwerk aus + Standard-Videoqualität im Wlan + Wähle die Standard-Videogeschwindigkeit + Standard Videogeschwindigkeit + ist nicht installiert. Bitte installieren. + "Paketname der Downloader-App wie NewPipe's oder PowerTube's" + Paketname des Downloaders + Standardeinstellungen für Downloader + Downloader-Einstellungen + Endbildschirm-Overlay wird angezeigt + Endbildschirm-Overlay sind ausgeblendet + Verstecke Endbildschirm-Overlay + Filmstreifen-Overlay wird angezeigt + Filmstreifen-Overlay ist versteckt + Verstecke Filmstreifen-Overlay + Deaktiviere Haptisches Feedback bei Kapiteln + Haptisches Feedback beim langen Drücken deaktivieren + Deaktiviere Haptisches Feedback + Haptisches Feedback beim Zoomen ist aktiviert + Haptisches Feedback beim Zoomen ist deaktiviert + Deaktiviere Haptisches Feedback beim Zoomen + Zeitstempel in Zwischenablage kopiert + Stätige automatische Wiederholung ist deaktiviert + Stätige automatische Wiederholung ist aktiviert + Stätige Auto-Wiederholung + Wischgesten deaktivieren, wenn Player-Steuerelemente sichtbar sind + Aktiviere immer Wischgesten unabhängig von der Player-Steuerung sichtbar oder nicht + Wischgesten immer aktivieren + Benutzerdefinierte Videogeschwindigkeit ist deaktiviert + Benutzerdefinierte Videogeschwindigkeit ist aktiviert + Aktiviere benutzerdefinierte Videogeschwindigkeit + Externer Browser ist deaktiviert + Externer Browser ist aktiviert + Aktiviere externen Browser + Automatische HDR Helligkeit ist deaktiviert + Automatische HDR Helligkeit ist aktiviert + Aktiviere automatische HDR-Helligkeit + Minimierte Wiedergabe ist deaktiviert + Minimierte Wiedergabe ist aktiviert + Minimierte Wiedergabe + YouTube Layout folgt Ihrem Google-Kontostatus + Umgehe die YouTube Version, um das neue Layout zu deaktivieren + Altes Layout aktivieren + Neuer Stil der Qualitätseinstellungen wird angezeigt + Alter Stil der Qualitätseinstellungen wird angezeigt + Aktiviere alten Stil der Qualitätseinstellungen + URL-Weiterleitung (youtube.com/redirect) wird verwendet, wenn Links in Videobeschreibungen geöffnet werden + Umgehe URL-Umleitungen (youtube.com/redirect) beim Öffnen von Links in Videobeschreibungen + Öffne Links direkt + Drücken zum Wischen ist deaktiviert + Drücken zum Wischen ist aktiviert + Drücken zum Wischen Geste + Umgehe die dpi, um einige Telefon-Layouts zu verwenden + Telefonlayout aktivieren + Tippen der Suchleiste (Video progress bar) ist deaktiviert + Speichert die Werte für die Videoqualität nicht, selbst wenn die Videoqualität geändert wird + Speichere den Wert der Videoqualität, wenn du die Videoqualität änderst + Aktiviere Videoqualität speichern + Tippen der Suchleiste (Video progress bar) ist aktiviert + Aktiviere Suchleisten-Tippen (Video progress bar) + Auch wenn die Helligkeit durch Wischen auf 0 gesetzt wird, ist die automatische Helligkeit nicht aktiviert + Wenn die Helligkeit durch Wischen 0 erreicht, wird die automatische Helligkeit aktiviert + Aktiviere Auto-Helligkeit durch Wischen + Helligkeit Wischen ist deaktiviert + Helligkeit Wischen ist aktiviert + Aktivieren der Helligkeitsgesten + Haptisches Feedback ist deaktiviert + Haptisches Feedback ist aktiviert + Aktiviere haptisches Feedback + Lautstärkegeste ist deaktiviert + Lautstärkegeste ist aktiviert + Aktiviere Lautstärkegesten + Tablet-Miniplayer ist deaktiviert + Tablet-Miniplayer ist aktiviert + Aktiviere Tablet-Miniplayer + Umgehe die dpi, um einige Tablet Layouts zu verwenden + Tablet Layout aktivieren + Breite Suchleiste ist deaktiviert + Breite Suchleiste ist aktiviert + Aktiviere breite Suchleiste + Experimentelle Flags + Probleme melden oder Vorschläge hier lassen + ReVanced Extended Problemcenter + ReVanced Extended Einstellungen + Erweiterte verwandte Einstellungen + Erweiterte Einstellungen + Behebung von Pufferproblemen ist deaktiviert + Behebung von Pufferproblemen ist aktivert + Behebung von Pufferproblemen + Untertitel werden aktiviert, wenn die Wiedergabe eines Videos mit Untertiteln erzwungen wird + "Untertitel werden nicht aktiviert, wenn die Wiedergabe eines Videos mit Untertiteln erzwungen wird" + Verstecke automatische Untertitel + Auto-Player Popup Fenster werden angezeigt + Auto-Player Popup Fenster sind versteckt + Verstecke Auto-Player Popup Fenster + Autoplay-Schaltfläche wird angezeigt + Autoplay-Schaltfläche ist versteckt + Verstecke Autoplay-Schaltfläche + Der Clip Button wird angezeigt + Der Clip Button ist versteckt + Verstecke Clip Button + Erstelle Short-Schaltfläche wird angezeigt + Erstelle Short-Schaltfläche ist ausgeblendet + Verstecke das Erstellen der Short-Schaltfläche + Der Dislike-Button wird angezeigt + Der Dislike-Button ist versteckt + Verstecke den Dislike-Button + Download-Schaltfläche wird angezeigt + Download-Schaltfläche ist ausgeblendet + Verstecke die Download-Schaltfläche + \"Gefällt mir\" Schaltfläche wird angezeigt + \"Gefällt mir\" Schaltfläche ist versteckt + Verstecke \"Gefällt mir\" Button + Live-Chat-Schaltfläche wird angezeigt + Live-Chat-Schaltfläche ist versteckt + Verstecke Live-Chat-Schaltfläche + Playlist Schaltfläche wird angezeigt + Playlist Schaltfläche ist versteckt + Verstecke Playlist Schaltfläche + Schaltfläche \"Bericht\" wird angezeigt + Schaltfläche \"Bericht\" ist versteckt + Berichtschaltfläche ausblenden + Teilen-Schaltfläche wird angezeigt + Teilen-Schaltfläche ist ausgeblendet + Verstecke \"Teilen\" Schaltfläche + Danke-Schaltfläche wird angezeigt + Danke-Schaltfläche ist versteckt + Verstecke \"Danke\" Schaltfläche + Schaltfläche \"Untertitel\" wird angezeigt + Schaltfläche \"Untertitel\" ist versteckt + Verstecke \"Untertitel\" Schaltfläche + Die Cast-Schaltfläche wird angezeigt + Die Cast-Schaltfläche ist versteckt + Verstecke Clip-Schaltfläche + Kanal-Wasserzeichen werden angezeigt + Kanal-Wasserzeichen sind versteckt + Verstecke Kanal-Wasserzeichen + Versteckt den Kommentarbereich oder die Elemente + Verstecke die Kommentar Elemente + Kommentarbereich wird angezeigt + Kommentar-Bereich ist versteckt + Verstecke den Kommentarbereich + Die Erstellen-Schaltfläche wird angezeigt + Die Erstellen-Schaltfläche ist versteckt + Verstecke Erstellen-Schaltfläche + Crowdfunding Box wird angezeigt + Crowdfunding Box ist versteckt + Verstecke Crowdfunding Box + E-Mail Adresse wird angezeigt + E-Mail Adresse ist versteckt + Verstecke E-Mail Adresse + Endbildschirmkarten werden angezeigt + Endbildschirmkarten sind versteckt + Verstecke Endbildschirmkarten + Infokarten werden angezeigt + Infokarten sind versteckt + Verstecke Infokarten + Ambient-Modus Menü wird angezeigt + Ambient Modus Menü ist versteckt + Verstecke Ambient-Modus + Audio-Track Menü wird angezeigt + Audio-Track Menü ist versteckt + Verstecke Audio-Track Menü + Untertitel-Menü wird angezeigt + Untertitel-Menü ist versteckt + Verstecke \"Untertitel\" Schaltfläche + Verstecke \"mehr Information\" Menü + Schaltfläche \"Bericht\" wird angezeigt + Schaltfläche \"Bericht\" ist versteckt + Verstecke Berichte + Verstecke Player-Overlay-Filter + Vorschau-Kommentar wird angezeigt + Vorschau-Kommentar ist versteckt + Verstecke Vorschau-Kommentar + Shorts Schaltfläche wird angezeigt + Shorts Schaltfläche ist versteckt + Verstecke \"Shorts\" Schaltfläche + Versteckt Shorts Abschnitt oder die Shorts Player-Elemente + Verstecke \"Shorts\" Elemente + Shorts Player Kommentarschaltfläche wird angezeigt + Shorts Player Kommentarschaltfläche ist versteckt + Verstecke Shorts Player Kommentarschaltfläche + Verstecke \"Shorts\" Elemente + Shorts Player Remix-Schaltfläche wird angezeigt + Shorts Player Remix-Schaltfläche ist versteckt + Verstecke Shorts Player Remix-Schaltfläche + Shorts-Player-Abonnements Schaltfläche wird angezeigt + Shorts-Player-Abonnements Schaltfläche ist versteckt + Verstecke Shorts-Player-Abonnements Schaltfläche + Shortspieler Danke Schaltfläche wird angezeigt + Shortspieler Danke Schaltfläche ist versteckt + Empfohlene Aktionen werden angezeigt + Vorgeschlagene Aktionen sind versteckt + Verstecke empfohlene Vorschläge + Zeit und Suchleiste werden angezeigt + Zeit und Suchleiste sind versteckt + Verstecke Zeit und Suchleiste + Layouteinstellungen des unteren Players + Flyout-Menü Layout Einstellungen + Vollbild-Layouteinstellungen + Allgemeine Layouteinstellungen + Player-Layout Einstellungen + Suchleisten-Layout Einstellungen + Layoutbezogene Einstellungen + Layouteinstellungen + Verschiedene verwandte Einstellungen + Sonstige Einstellungen + Andere + Auto-Wiederholen Schaltfläche ist ausgeblendet + Auto-Wiederholen Schaltfläche wird angezeigt + Zeige Auto-Wiederholen Schaltfläche + Premium-Header + „Return YouTube Dislike“ Einstellungen + ReVanced Einstellungen + Videoeinstellungen + Videowerbung + Werbung + Kanalname + Keine Kanäle auf der Whitelist vorhanden + Zur Whitelist hinzugefügt + Kanal-Whitelist + Whitelist Einstellungen + Videogeschwindigkeit + Geschwindigkeit + SponsorBlock + SB + Bereits gelesen + Zeig es mir + Es gibt Richtlinien + Richtlinien anzeigen + SponsorBlock Einstellungen + Endkarten/Credits + Füller/Witze + Unterbrechung/Introanimation + Musik: Nicht-Musik-Bereich + Übersprungen einer Nicht-Musik-Sektion + Vorschau übersprungen + Sponsor-Segment übersprungen + Eigenwerbung übersprungen + Sponsor übersprungen + Nervige Erinnerung übersprungen + Nicht übermitteltes Segment übersprungen + Statistiken + Lädt … + "Du hast Zuschauer bereits vor <b>%s</b> Segmenten bewahrt." + Segment wird gesendet… + Segment erfolgreich gesendet + Tippen zum Überspringen + Kategorie ändern + Downvote + "Kann nicht für das Segment abstimmen. + +%s" + "Kann nicht für das Segment abstimmen. +Rate limitiert (zu viele von demselben Benutzer oder IP)" + Kann nicht für Segment abstimmen: Status: %d %s + Es gibt keine Segmente zur Abstimmung + Abstimmung für das Segment läuft… + erfolgreich abgestimmt + Upvote + diff --git a/src/main/resources/youtube/translations/es-rES/strings.xml b/src/main/resources/youtube/translations/es-rES/strings.xml new file mode 100644 index 000000000..c8b9a46ae --- /dev/null +++ b/src/main/resources/youtube/translations/es-rES/strings.xml @@ -0,0 +1,591 @@ + + + Información + Esta aplicación utiliza la API de SponsorBlock + Toque para aprender más y ver descargas para otras plataformas en: sponsor.ajay.app + Integración hecha por JakubWeg + ¿Activar los controles de accesibilidad para el reproductor de vídeo? + Sus controles se modifican porque un servicio de accesibilidad está activado. + La URL de la API fue cambiada + La URL de la API proveída no es válida + La URL de la API fue restablecida + La URL del Mirror de la API fue cambiada + La URL del Mirror de la API no es válida + La URL del Mirror de la API fue restablecida + ¿Estás buscando cambiar los colores? + "\"Ahora puedes cambiar el color de una categoría pulsando en ella arriba\"." + Color cambiado + Código hexadecimal no válido + Color restablecido + ¿Qué hacer con los diferentes segmentos? + Activar SponsorBlock + SponsorBlock es un sistema colaborativo para omitir partes molestas en vídeos de YouTube + Activar Mirror de SponsorBlock + Cuando el servidor de la API de SponsorBlock se cae, cambia el servidor Mirror de la API al servidor API predeterminado + Activar adición de nuevos segmentos + Active esta opción para permitir la adición experimental de segmentos (tiene problemas de visibilidad de los botones) + Activar votación + Active esta opción para permitir la votación. + General + Ajustar paso de nuevo segmento + Esta es la cantidad de milisegundos que puede moverse cuando usa los botones de ajuste de tiempo mientras añade un nuevo segmento + Cambiar la URL de la API + "La dirección que utiliza SponsorBlock para hacer llamadas al servidor. <b>No cambie esto a menos que sepa lo que está haciendo.</b>" + Cambiar la URL del Mirror de la API + "Dirección del servidor Mirror para cambiar cuando el servidor de SponsorBlock esté caido. <b>No cambie esto a menos que sepa lo que está haciendo.</b>" + Duración mínima del segmento + Los segmentos más cortos que el valor establecido (en segundos) no se omitirán ni se mostrarán en el reproductor + Rastreo de cantidad de omisiones + Esto permite que el sistema de clasificación de SponsorBlock sepa cuánto tiempo han ahorrado las personas. La extensión envía un mensaje al servidor cada vez que omites un segmento + Mostrar mensaje al omitir segmento automáticamente + Clic para mirar un ejemplo de aviso + Mostrar tiempo sin segmentos + Este tiempo aparece entre paréntesis junto al tiempo actual. Muestra la duración total del vídeo sin ningún segmento. + Su ID de usuario privado + Esto debe mantenerse en privado. Es como una contraseña y no debe compartirse con nadie. Si alguien lo tiene, puede hacerse pasar por ti + Por favor, instale MicroG + MicroG no se encuentra + Ajustes de notificaciones + "\"1. El registro de dispositivos de Google y Cloud Messaging deben estar activados para recibir notificaciones. +2. ReVanced debe mostrarse como registrado en Cloud Messaging. +3. El estado actual en Cloud Messaging debe ser Conectado\"." + Ajustes de MicroG + minutos + Elija la categoría del segmento + "El segmento dura de %02d:%02d a %02d:%02d (%d minutos %02d segundos) +¿Está listo para enviarlo?" + ¿Son correctos los tiempos? + "Has desactivado esta categoría en los ajustes, actívela para poder enviar segmentos" + ¿Desea editar el tiempo para el inicio o el final del segmento? + Tiempo no válido + Listo + Editar el tiempo del segmento manualmente + fin + Primero marque dos ubicaciones en la barra de tiempo + inicio + ¿Establecer %02d:%02d:%04d como el inicio o el final de un nuevo segmento? + ahora + Tiempo en que finaliza el segmento + Establecido el final del segmento + Tiempo en que comienza el segmento + Establecido el inicio del segmento + Nuevo segmento de SponsorBlock + Reiniciar + Ajustes relacionados con anuncios + Ajustes de anuncios + Las tarjetas de álbum están visibles en los resultados de búsqueda + Las tarjetas de álbum están ocultas en los resultados de búsqueda + Ocultar tarjetas de álbum + Los estantes de noticias de última hora están visibles + Los estantes de noticias de última hora están ocultos + Ocultar estantes de noticias de última hora + Los anuncios con botones están visibles + Los anuncios con botones están ocultos + Ocultar anuncios con botones + Las normas de los canales están visibles + Las normas de los canales están ocultas + Ocultar normas de canales + Los avances de los capítulos están visibles + Los avances de los capítulos están ocultos + Ocultar avances de capítulos debajo de vídeos + Las normas comunitarias están visibles + Las normas comunitarias están ocultas + Ocultar normas comunitarias + Las publicaciones comunitarias están visibles + Las publicaciones comunitarias están ocultas + Ocultar publicaciones comunitarias + Los banners compactos están visibles + Los banners compactos están ocultos + Ocultar banners compactos + Filtrar componentes por su nombre separados por una coma + Filtro personalizado + Los cuadros de emergencia están visibles + Los cuadros de emergencia están ocultos + Ocultar cuadros de emergencia + Los anuncios generales están visibles + Los anuncios generales están ocultos + Ocultar anuncios generales + Los estantes de imágenes están visibles + Los estantes de imágenes están ocultos + Ocultar estantes de imágenes + Los paneles de información están visibles + Los paneles de información están ocultos + Ocultar paneles de información + Las encuestas están visibles + Las encuestas están ocultas + Ocultar encuestas + Las últimas publicaciones están visibles + Las últimas publicaciones están ocultas + Ocultar últimas publicaciones + Los paneles médicos están visibles + Los paneles médicos están ocultos + Ocultar paneles médicos + Los banners de mercancía están visibles + Los banners de mercancía están ocultos + Ocultar banners de mercancía + Los estantes de películas están visibles + Los estantes de películas están ocultos + Ocultar estantes de películas + Las tarjetas oficiales están visibles en los resultados de búsqueda + Las tarjetas oficiales están ocultas en los resultados de búsqueda + Ocultar tarjetas oficiales + El contenido de pago está visible + El contenido de pago está oculto + Ocultar contenido de pago + Las tarjetas autopatrocinadas están visibles + Las tarjetas autopatrocinadas están ocultas + Ocultar tarjetas autopatrocinadas + Los separadores grises están visibles + Los separadores grises están ocultos + Ocultar separadores grises + Las sugerencias están visibles + Las sugerencias están ocultas + Ocultar sugerencias + Las reacciones cronometradas están visibles + Las reacciones cronometradas están ocultas + Ocultar reacciones cronometradas + El filtro de usuario está desactivado + El filtro de usuario está activado + Activar filtro de usuario + El banner de ver productos está visible + El banner de ver productos está oculto + Ocultar banner de ver productos + Los paneles de búsqueda web están visibles + Los paneles de búsqueda web están ocultos + Ocultar paneles de búsqueda web + La duración máxima de los medios que el reproductor intentará almacenar en el búfer + Tamaño máximo de búfer + La duración de los medios que deben almacenarse en búfer para que la reproducción comience o se reanude después de una acción del usuario, como desplazarse en la barra de progreso + Tamaño del búfer de inicio de reproducción + La duración de los medios que deben almacenarse en búfer para que la reproducción se reanude después de un rebufer + Tamaño del rebufer + Ajustes relacionados con el tamaño del búfer de vídeo + Ajustes del búfer de vídeo + Seleccione la resolución de vídeo predeterminada en la red móvil + Calidad de vídeo predeterminada en red móvil + Seleccione la resolución de vídeo predeterminada en la red Wi-Fi + Calidad de vídeo predeterminada en red Wi-Fi + Seleccione la velocidad de vídeo predeterminada + Velocidad de vídeo predeterminada + no está instalado. Por favor, instálelo. + "Nombre del paquete de la aplicación de descargas, como NewPipe o PowerTube" + Nombre del paquete del descargador + Ajustes relacionados con el descargador predeterminado + Ajustes del descargador + La superposición de la pantalla final está visible + La superposición de la pantalla final está oculta + Ocultar superposición de pantalla final + La superposición de la tira de película está visible + La superposición de la tira de película está oculta + Ocultar superposición de tira de película + La vibración al deslizar está activada + La vibración al deslizar está desactivada + Desactivar vibración al deslizar + La vibración al desplazarse está activada + La vibración al desplazarse está desactivada + Desactivar vibración al desplazarse + La vibración de los capítulos está activada + La vibración de los capítulos está desactivada + Desactivar vibración de los capítulos + Desactivar vibración al mantener presionado + Desactivar vibración + La vibración al hacer zoom está activada + La vibración al hacer zoom está desactivada + Desactivar vibración al hacer zoom + Marca de tiempo copiada al portapapeles + La repetición automática está desactivada + La repetición automática está activada + Repetir siempre automáticamente + Desactiva los gestos de deslizamiento cuando los controles del reproductor estén visibles + Activa siempre los gestos de deslizamiento, independientemente de si los controles del reproductor están visibles o no + Activar siempre los gestos de deslizamiento + La velocidad de vídeo personalizada está desactivada + La velocidad de vídeo personalizada está activada + Activar velocidad de vídeo personalizada + El navegador externo está desactivado + El navegador externo está activado + Activar navegador externo + El brillo HDR automático está desactivado + El brillo HDR automático está activado + Activar brillo HDR automático + La reproducción en segundo plano está desactivada + La reproducción en segundo plano está activada + Activar reproducción en segundo plano + El diseño de YouTube seguirá el estado de su cuenta de Google + Modifica la versión de YouTube para forzar la desactivación del nuevo diseño + Activar diseño antiguo + El estilo antiguo del ajuste de calidad está visible + El estilo antiguo del ajuste de calidad está visible + Activar estilo antiguo del diseño de calidad + La redirección de URL (youtube.com/redirect) se usa al abrir enlaces en las descripciones de los vídeos + Omite los redireccionamientos de URL (youtube.com/redirect) al abrir enlaces en las descripciones de los vídeos + Activar apertura de enlaces directamente + El gesto de presionar para deslizar está desactivado + El gesto de presionar para deslizar está activado + Activar gesto de presionar para deslizar + La pulsación en la barra de progreso está desactivada + No se guardan los valores de calidad del vídeo incluso cuando cambia la calidad del vídeo + Se guarda el valor de la calidad del vídeo cada vez que cambia la calidad del vídeo + Activar guardado de calidad de vídeo + La pulsación en la barra de progreso está activada + Activar pulsación en barra de progreso + Incluso si el brillo se establece en 0 al deslizar, el brillo automático no está activado + Cuando el brillo llega a 0 al deslizar, se activa el brillo automático + Activar brillo automático al deslizar + El control del brillo al deslizar está desactivado + El control del brillo al deslizar está activado + Activar control del brillo al deslizar + La vibración al presionar para deslizar está desactivada + La vibración al presionar para deslizar está activada + Activar vibración al presionar para deslizar + El control del volumen al deslizar está desactivado + El control del volumen al deslizar está activado + Activar control del volumen al deslizar + El minirreproductor para tabletas está desactivado + El minirreproductor para tabletas está activado + Activar minirreproductor para tabletas + La barra de búsqueda ancha está desactivada + La barra de búsqueda ancha está activada + Activar barra de búsqueda ancha + Funciones experimentales + Informe problemas o deje sugerencias aquí + Centro de problemas de ReVanced Extended + Ajustes de ReVanced Extended + Ajustes relacionados con Extended + Ajustes de Extended + Los subtítulos se activan cuando la reproducción de un vídeo con subtítulos es obligatoria + "Los subtítulos no están activados cuando la reproducción de un vídeo con subtítulos es obligatoria" + Ocultar subtítulos automáticos + Los paneles emergentes del reproductor automático están visibles + Los paneles emergentes del reproductor automático están ocultos + Ocultar paneles emergentes del reproductor automático + El botón de reproducción automática está visible + El botón de reproducción automática está oculto + Ocultar botón de reproducción automática + Ocultar los componentes del contenedor de botones + Ocultar componentes del contenedor de botones + El botón Clip está visible + El botón Clip está oculto + Ocultar botón Clip + El botón de crear Short está visible + El botón de crear Short está oculto + Ocultar botón de crear Short + El botón No Me Gusta está visible + El botón No Me Gusta está oculto + Ocultar botón No Me Gusta + El botón Descargar está visible + El botón Descargar está oculto + Ocultar botón Descargar + Ell botón Me Gusta está visible + El botón Me Gusta está oculto + Ocultar botón Me Gusta + El botón Chat En Directo está visible + El botón Chat En Directo está oculto + Ocultar botón Chat En Directo + El botón de lista de reproducción está visible + El botón de lista de reproducción está oculto + Ocultar botón de lista de reproducción + El botón Denunciar está visible + El botón Denunciar está oculto + Ocultar botón Denunciar + El botón Compartir está visible + El botón Compartir está oculto + Ocultar botón Compartir + El botón Gracias está visible + El botón Gracias está oculto + Ocultar botón Gracias + El botón Subtítulos está visible + El botón Subtítulos está oculto + Ocultar botón Subtítulos + El botón Transmitir está visible + El botón Transmitir está oculto + Ocultar botón Transmitir + La marca de agua del canal está visible + La marca de agua del canal está oculta + Ocultar marca de agua del canal + Ocultar las secciones de comentarios o los componentes + Ocultar componentes de comentarios + La sección de comentarios está visible + La sección de comentarios está oculta + Ocultar sección de comentarios + El botón Crear está visible + El botón Crear está oculto + Ocultar botón Crear + El cuadro de Crowdfunding está visible + El cuadro de Crowdfunding está oculto + Ocultar cuadro de Crowdfunding + La dirección de correo electrónico está visible + La dirección de correo electrónico está oculta + Ocultar dirección de correo electrónico + Las tarjetas de la pantalla final están visibles + Las tarjetas de la pantalla final están ocultas + Ocultar tarjetas de pantalla final + El contenedor de botones en pantalla completa está visible + El contenedor de botones en pantalla completa está oculto + Ocultar contenedor de botones en pantalla completa + Las tarjetas de información están visibles + Las tarjetas de información están ocultas + Ocultar tarjetas de información + El menú Modo Ambiente está visible + El menú Modo Ambiente está oculto + Ocultar menú Modo Ambiente + El menú Pista de Audio está visible + El menú Pista de Audio está oculto + Ocultar menú Pista de Audio + El menú Subtítulos está visible + El menú Subtítulos está oculto + Ocultar menú Subtítulos + El menú Ayuda y Comentarios está visible + El menú Ayuda y Comentarios está visible + Ocultar menú Ayuda y Comentarios + El menú Controles Auditivos está visible + El menú Controles Auditivos está oculto + Ocultar menú Controles Auditivos + El menú Escuchar con YouTube Music está visible + El menú Escuchar con YouTube Music está oculto + Ocultar menú Escuchar con YouTube Music + El menú Reproducción en Bucle está visible + El menú Reproducción en Bucle está oculto + Ocultar menú Reproducción en Bucle + El menú Más Información está visible + El menú Más Información está oculto + Ocultar menú Más Información + El menú Denunciar está visible + El menú Denunciar está oculto + Ocultar menú Denunciar + El menú Estadísticas para Nerds está visible + El menú Estadísticas para Nerds está oculto + Ocultar menú Estadísticas para Nerds + El menú Ver en Realidad Virtual está visible + El menú Ver en Realidad Virtual está oculto + Ocultar menú Ver en Realidad Virtual + La lista de reproducción Mix está visible + La lista de reproducción Mix está oculta + Ocultar lista de reproducción Mix + El filtro de superposición del reproductor está visible + El filtro de superposición del reproductor está oculto + Ocultar filtro de superposición del reproductor + La vista previa de comentarios está visible + La vista previa de comentarios está oculta + Ocultar vista previa de comentarios + El botón Shorts está visible + El botón Shorts está oculto + Ocultar botón Shorts + Ocultar las secciones de Shorts o los componentes del reproductor de Shorts + Ocultar componentes de Shorts + El botón de comentarios en el reproductor de Shorts está visible + El botón de comentarios en el reproductor de Shorts está oculto + Ocultar botón de comentarios en reproductor de Shorts + Ocultar componentes del reproductor de Shorts + El botón de remezcla en el reproductor de Shorts está visible + El botón de remezcla en el reproductor de Shorts está oculto + Ocultar botón de remezcla en reproductor de Shorts + El botón de suscripción en el reproductor de Shorts está visible + El botón de suscripción en el reproductor de Shorts está oculto + Ocultar botón de suscripción en reproductor de Shorts + El botón de agradecimiento en el reproductor de Shorts está visible + El botón de agradecimiento en el reproductor de Shorts está oculto + Ocultar botón de agradecimiento en reproductor de Shorts + Los estantes de Shorts están visibles + Los estantes de Shorts están ocultos + Ocultar estante de Shorts + El reproductor de Shorts está desactivado al iniciar la aplicación + El reproductor de Shorts está activado al iniciar la aplicación + Reproductor de Shorts al iniciar la aplicación + Los estantes de las historias están visibles + Los estantes de las historias están ocultos + Ocultar estantes de historias + Las acciones sugeridas están visibles + Las acciones sugeridas están ocultas + Ocultar acciones sugeridas + El tiempo y la barra de progreso están visibles + El tiempo y la barra de progreso están ocultos + Ocultar tiempo y barra de progreso + Ajustes de diseño del reproductor inferior + Ajustes de diseño del menú desplegable + Ajustes de diseño de pantalla completa + Ajustes generales de diseño + Ajustes de diseño del reproductor + Ajustes de diseño de la barra de progreso + Ajustes relacionados con el diseño + Ajustes de diseño + Ajustes relacionados con otros + Ajustes de otros + Otros + El botón de repetición automática está oculto + El botón de repetición automática está visible + Mostrar botón de repetición automática + El botón de copiar enlace está oculto + El botón de copiar enlace está visible + Mostrar botón de copiar enlace + El botón de copiar enlace con marca de tiempo está oculto + El botón de copiar enlace con marca de tiempo está visible + Mostrar botón de copiar enlace con marca de tiempo + El botón de descarga está oculto + El botón de descarga está visible + Mostrar botón de descarga + Ajustes relacionados con botones de superposiciones + Ajustes de botones de superposiciones + El botón de lista blanca está oculto + El botón de lista blanca está visible + Mostrar botón de lista blanca + Encabezado actual: encabezado predeterminado + Encabezado actual: Encabezado Premium + Encabezado Premium + Información sobre los parches aplicados + Información de parches + Ocultar los componentes del panel flotante de los ajustes del reproductor + Componentes del panel flotante del reproductor + Los datos de No Me Gusta son proporcionados por la API True RYD Worker. Toque aquí para obtener más información. + true-ryd.cane.workers.dev + El Mirror de la API está desactivado + El Mirror de la API está activado + Activar Mirror de la API + "La API True RYD Worker utiliza el recuento de No Me Gusta expuesto en el punto final de la API de YouTube. + +Active esta opción solo para aquellos que experimentan problemas al usar la API de RYD predeterminada. + +¿Quieres continuar?" + True RYD Worker + Los datos de No Me Gusta son proporcionados por la API Return YouTube Dislike. Toque aquí para obtener más información. + ReturnYouTubeDislike.com + No Me Gusta mostrado como número + No Me Gusta mostrado como porcentaje + No Me Gusta como porcentaje + Los No Me Gusta están ocultos + Los No Me Gusta están visibles + Return YouTube Dislike + Los No Me Gusta no están disponibles (se alcanzó el límite de la API del cliente) + ReturnYouTubeDislike no pudo confirmar el nuevo usuario + ReturnYouTubeDislike no pudo confirmar el voto + Los No Me Gusta están temporalmente no disponibles (la API agotó el tiempo de espera) + ReturnYouTubeDislike no pudo registrarse como nuevo usuario + ReturnYouTubeDislike no pudo enviar el voto + Ajustes para Return YouTube Dislike + Return YouTube Dislike + Ajustes de ReVanced + Ajustes relacionados con los controles de deslizamiento + Ajustes de controles de deslizamiento + La cantidad de umbral para que ocurra el deslizamiento + Umbral de magnitud de deslizamiento + La visibilidad del fondo de superposición de deslizamiento + Visibilidad de fondo de deslizamiento + El tamaño del texto para la superposición de deslizamiento + Tamaño del texto de superposición de deslizamiento + La cantidad de milisegundos que la superposición es visible + Tiempo de espera de superposición de deslizamiento + Herramienta utilizada + Los anuncios de vídeo están visibles + Los anuncios de vídeo están ocultos + Ocultar anuncios de vídeo + Error al establecer la calidad + Sin conexión a Internet + Cambio de la calidad predeterminada para datos móviles a: + No se pudo cambiar la calidad predeterminada para datos móviles + Cambio de la calidad predeterminada para Wi-Fi a: + No se pudo cambiar la calidad predeterminada para Wi-Fi + Ajustes relacionadas con vídeo + Ajustes de vídeo + Error al añadir el canal %s a la lista blanca %s + El canal %s fue añadido a la lista blanca %s + Anuncios de vídeo + Anuncios + Nombre del canal + No hay canales en la lista blanca + No añadido a la lista blanca + Añadido a la lista blanca + Lista blanca de canales + Error al recuperar los detalles del canal, código recibido %d + Reiniciar para aplicar los ajustes de la lista blanca de canales + No se pudo eliminar el canal %s de la lista blanca %s + El canal %s fue eliminado de la lista blanca %s + Ajustes relacionados con la lista blanca de canales + Ajustes de la lista blanca + Velocidad de vídeo + Velocidad + SponsorBlock + SB + ¡El servidor de Sponsorblock no responde! + Ya leído + "Se recomienda leer las normas de SponsorBlock antes de enviar cualquier segmento" + Muéstrame + Hay normas + Las normas contienen consejos y reglas sobre el envío de segmentos + Ver normas + Ajustes de SponsorBlock + Ajustes relacionados con SponsorBlock + Cambiado correctamente. recargar el vídeo + Cambio del servidor Mirror de la API al servidor principal de la API. + Tarjetas finales/Créditos + Créditos o cuando aparecen las tarjetas finales de YouTube. No es para las conclusiones habladas + Tangente de relleno/Chistes + Escenas tangenciales añadidas solo para relleno o humor que no son requeridas para entender el contenido principal del vídeo. Esto no debe incluir detalles de contexto o fondo + Intermisión/animación de introducción + Un intervalo sin contenido real. Podría ser una pausa, imagen estática, animación que se repite + Música: Sección sin música + Solamente para utilizar en vídeos de música. Omite partes del vídeo que no están en las mezclas oficiales + Vista previa/Resumen + "\"Recapitulación de episodios anteriores, o una vista previa de lo que aparece más tarde en el vídeo actual o en los vídeos futuros de la misma serie. Los clips no deben proporcionar información adicional\"." + No pagado/Autopromoción + Cuando hay promoción propia o no pagada. Esto incluye secciones específicas sobre mercancía, donaciones o información sobre con quién colaboraron + Patrocinador + Promoción pagada, referencias pagadas y anuncios directos + Recordatorio de interacción (suscripción) + Cuando hay un pequeño recordatorio para darle me gusta, suscribirse, seguirlos o interactuar con ellos en cualquier plataforma gratuita o de pago + No se pudo exportar la configuración + Importar/exportar configuración + Esta es su configuración completa que es aplicable en la extensión de escritorio en JSON. Esto incluye su ID de usuario privado, así que asegúrese de compartirla sabiamente. + No se pudo importar la configuración + La configuración se importó correctamente + Omitir automáticamente + Omitir automáticamente una vez + "No hacer nada" + Mostrar botón de omitir + Omitir segmento + Créditos omitidos + Relleno omitido + Introducción omitida + Sección sin música omitida + Resumen omitido + Segmento de patrocinador omitido + Autopromoción omitida + Patrocinador omitido + Recordatorio molesto omitido + Segmento no enviado omitido + Estadísticas + Cargando... + "\"Has salvado personas de <b>%s</b> segmentos\"." + "Eso es <b>%s</b> de sus vidas. Pulse para ver la clasificación" + SponsorBlock está desactivado + "\"Has omitido <b>%s</b> segmentos\"." + "\"Eso es <b>%s</b>\"." + Envíos: <b>%s</b> + Su nombre de usuario: <b>%s</b> + Pulse para cambiar su nombre de usuario + No se puede cambiar el nombre de usuario: Estado: %d %s + Nombre de usuario cambiado correctamente + "No se puede enviar el segmento. +Ya existe" + "No se puede enviar el segmento. + +%s" + "No se puede enviar el segmento. +Tasa limitada (demasiada del mismo usuario o IP)" + No se puede enviar el segmento: %s + No se pueden enviar segmentos: Estado: %d %s + Enviando segmento… + Segmento enviado correctamente + Toque para omitir + Cambiar categoría + Voto negativo + "No se puede votar por el segmento. + +%s" + "No se puede votar por segmento. +Tasa limitada (demasiada del mismo usuario o IP)" + No se puede votar por el segmento: Estado: %d %s + No hay segmentos por los cuales votar + Votando por el segmento... + Votado correctamente + Voto positivo + diff --git a/src/main/resources/youtube/translations/fr-rFR/strings.xml b/src/main/resources/youtube/translations/fr-rFR/strings.xml new file mode 100644 index 000000000..f49ab7c3d --- /dev/null +++ b/src/main/resources/youtube/translations/fr-rFR/strings.xml @@ -0,0 +1,611 @@ + + + A propos + Cette application utilise l\'API de SponsorBlock + Cliquez pour voire lez téléchargement sur d\'autres plateformes + Intégration faite par JakubWeg + Activer les contrôles d\'accessibilités pour le lecteur vidéo? + Vos contrôles sont modifiés car un service d\'accessibilité est activé. + URL de l\'API modifiée + L\'URL de l\'API fournie n\'est pas valide + Réinitialiser l\'URL de l\'API + URL API MIRROR modifiée + L’URL API MIRROR fournie n’est pas valide + API MIRROR URL réinitialiser + Vous cherchez à changer les couleurs ? + "Vous pouvez maintenant changer la couleur d'une catégorie en cliquant dessus." + Couleur modifiée + Code hexadécimal non valide + Couleur réinitialiser + Que faire avec les différents moments + Activer SponsorBlock + SponsorBlock est un système populaire pour passer des parties ennuyeuses dans les vidéos YouTube + Activer SponsorBlock Mirror + Lorsque le serveur d’API SponsorBlock est arrêté, basculer le serveur d’API miroir sur le serveur d’API par défaut + Activer l’ajout de nouveaux moments + Activer cette option pour permettre l’ajout d’un moment expérimental (problèmes de visibilité des boutons) + Activer le vote + Allumez-le pour permettre le vote. + Général + Ajustement d’un nouveau étape de moment + C’est le nombre de millisecondes que vous pouvez déplacer lorsque vous utilisez les boutons de réglage du temps tout en ajoutant un nouveau moment + Modifier L\'URL de L\'API + "L’adresse utilisée par SponsorBlock pour faire des appels au serveur. <b>Ne changez rien à moins de savoir ce que vous faites. </b>" + Modifier l’URL du miroir de l’API + "L'adresse miroir utilisée lorsque le serveur SponsorBlock est désactivé. <b>Ne changez rien à moins de savoir ce que vous faites. </b>" + Durée minimum du moment + Les moments plus courts que la valeur définie (en secondes) ne seront pas passées ou affichés dans le lecteur + Suivi des sauts de compte(Nombre de fois ou le moment a été passée) + Cela permet au système de classement SponsorBlock de savoir combien de temps les gens ont économisé. L’extension envoie un message au serveur chaque fois que vous passez un moments + Afficher un message lorsque vous sautez un segment automatiquement + Cliquez pour voir un exemple de message + Temps d’affichage sans moment a passer + Cette heure apparaît entre parenthèses à côté de l’heure actuelle. Elle indique la durée totale de la vidéo avec les moments que vous devrez passez + Votre code d’utilisateur privé + Cela doit rester privé. C’est comme un mot de passe et ne doit pas être partagé avec quiconque. Si quelqu’un a cela, ils peuvent se faire passer pour vous + Veuillez installer MicroG + MicroG n’est pas trouvé + Paramètres de notifications + "1. L’enregistrement des appareils Google et la Messagerie Cloud doivent être activés pour les notifications. +2. ReVanced doit être affiché comme enregistré sous Messagerie Cloud +3. L’état actuel de la Messagerie Cloud doit être connecté.\"" + Paramètres MicroG + minutes + Choisir la catégorie de moment + "Le moment dure de %02d:%02d à %02d:%02d (%d minutes %02d secondes) +Est-il prêt à être soumis?" + Les temps sont-ils corrects ? + "Vous avez désactivé cette catégorie dans les paramètres, activez-la pour pouvoir soumettre" + Voulez-vous modifier le temps pour le début ou la fin du moment ? + Temps non valide + Terminé + Editer le temps du moment manuellement + Fin + Tout d\'abord marquer deux emplacements sur la barre de temps + Début + Définir %02d:%02d:%04d comme début ou fin d\'un nouveau moment ? + Maintenant + Définir la fin du moment à + Fin de l\'ensemble du moment + Définir le début du moment à + Début de l\'ensemble du moment + Nouveau moment SponsorBlock + Réinitialiser + Paramètres liés aux publicités + Paramètres des pubs + Les cartes d’album sont affichées à partir des résultats de recherche + Les cartes d’album sont cachées des résultats de recherche + Cacher la couverture de l\'album + Les nouvelles de dernière heure sont affichées + Les nouvelles de dernière heure sont cachées + Cacher l’étagère des dernières nouvelles + Les annonces boutonnées sont affichées + Des annonces boutonnées sont cachées + Cacher les pub boutonnée + Les directives relatives aux chaînes sont affichées + Les directives relatives aux chaînes sont cachées + Cacher les directives relatives aux chaînes + Les teasers de chapitre sont affichées + Les teasers de chapitre sont cachées + Masquer le teaser des chapitres sous les vidéos + Les orientations communautaires sont affichées + Les orientations communautaires sont cachées + Cacher les orientations communautaires + Les publications communautaires sont affichées + Les publications communautaires sont cachées + Cacher les publications communautaires + Les bannières compactes sont affichées + Les bannières compactes sont cachées + Cacher les bannières compactes + Filtre les composants par leur nom séparé par une virgule + Filtre personnalisé + Les boîtes d\'urgence sont affichées + Les boîtes d\'urgence sont cachées + Cacher les boîtes d\'urgence + Les annonces sont affichées + Les annonces sont cachées + Cacher les annonces + Les étagères d\'images sont affichées + Les étagères d\'images sont cachées + Cacher l\'étagère d\'image + Les panneaux d\'information sont affichés + Les panneaux d\'information sont cachés + Cacher les panneaux d\'information + Les sondages de flux sont affichés + Les sondages de flux sont cachés + Cacher les sondages de flux + Les dernières publications sont affichées + Les dernières publications sont cachées + Cacher les dernières publications + Les panneaux médicaux sont affichés + Les panneaux médicaux sont cachés + Cacher les panneaux médicaux + Les bannières de marchandise sont affichées + Les bannières de marchandise sont cachées + Cacher les bannières de marchandise + Les étagères de films sont affichées + Les étagères de films sont cachées + Cacher l\'étagère de films + Les cartes officielles sont affichées à partir des résultats de recherche + Les cartes officielles sont cachées à partir des résultats de recherche + Cacher les cartes officielles + Le contenu payant est affiché + Le contenu payé est caché + Cacher le contenu payé + Les cartes auto-sponsorisées sont affichées + Les cartes auto-sponsorisées sont cachées + Cacher les cartes auto-sponsorisées + Les séparateurs gris sont affichés + Les séparateurs gris sont cachés + Cacher le séparateur gris + Les suggestions sont affichées + Les suggestions sont cachées + Cacher les suggestions + Les réactions chronométrées sont affichées + Les réactions chronométrées sont cachées + Cacher les réactions chronométrés + Le filtre d\'utilisateur est désactivé + Le filtre d\'utilisateur est activé + Activer le filtre d\'utilisateur + La bannière des produits est affichée + La bannière des produits est cachée + Cacher la bannière des produits + Les panneaux de recherche Web sont affichés + Les panneaux de recherche Web sont cachés + Cacher les panneaux de recherche web + La durée maximale du média que le lecteur tentera de mettre en mémoire tampon + Mémoire tampon maximum + La durée des supports qui doivent être mis en mémoire tampon pour que la lecture commence ou reprenne après une action de l’utilisateur telle que la recherche + Taille du tampon de début de lecture + La durée des supports qui doivent être mis en mémoire tampon pour que la lecture reprenne après un tampon supplémentaire + Taille du tampon supplémentaire + Paramètres liés à la taille du tampon vidéo + Paramètres du tampon vidéo + Sélectionnez la résolution vidéo par défaut sur les données mobiles + Qualité vidéo par défaut données mobiles + Sélectionnez la résolution par défaut des vidéos sur le réseau Wi-Fi + Qualité vidéo par défaut Wi-Fi + Sélectionnez la vitesse de la vidéo par défaut + Vitesse par défaut des vidéos + n’est pas installé. Veuillez l’installer + "Nom du paquet de l'application de téléchargement tel que NewPipe ou PowerTube" + Nom du paquet du téléchargeur + Paramètres par défaut liés au téléchageur + Paramètres du téléchargeur + Les superpositions d’écran de fin son affichés + Les superpositions d’écran de fin sont cachées + Cacher les superpositions d’écran de fin + Les superpositions de bandes de film sont affichées + Les superpositions de bandes de film sont cachées + Cacher les superpositions de bandes de film + La rétroaction haptique de nettoyage est activée + La rétroaction haptique de nettoyage est désactivé + Désactivé la rétroaction haptique de nettoyage + La recherche de rétroaction haptique est activée + Recherche de rétroaction haptique désactivé + Désactiver la recherche de rétroaction haptique + Le chapitre de rétroaction haptique est activée + Le chapitre de rétroaction haptique est désactivée + Désactiver le chapitre de rétroaction haptique + Désactiver la rétroaction haptique via une longue pression + Désactiver la rétroaction haptique + La rétroaction haptique de zoom est activée + La rétroaction haptique de zoom est désactivée + Désactiver la rétroaction haptique du zoom + Le texte horodateur a été copié dans le presse-papiers + La répétition automatique est toujours désactivée + La répétition automatique est toujours activée + Toujours répéter automatiquement + Désactiver les gestes de balayage lorsque les commandes du lecteur sont visibles + Toujours activer les gestes de balayage lorsque les commandes du joueur sont visibles ou non + Toujours activer les gestes de balayage + La vitesse de lecture personnalisée est désactivée + La vitesse de lecture personnalisée est activée + Activer la vitesse de vidéo personnalisée + Le navigateur externe est désactivé + Le navigateur externe est activé + Activer le navigateur externe + Luminosité HDR automatique désactivée (Luminosité dynamique) + Luminosité HDR automatique activée (Luminosité dynamique) + Activer la luminosité automatique HDR (Luminosité dynamique) + Lecture minimisée désactivée + Lecteur minimisée activité + Activer le lecteur minimisée + La mise en page YouTube suivra l\'état de votre compte Google + Option pour forcer l\'activation de l\'ancienne mise en page YouTube + Activer l\'ancienne mise en page + La nouvelle interface des paramètres de qualité vidéo est caché + L\'ancienne interface de paramètres de qualité vidéo est affiché + Activer l\'ancienne interface de qualité vidéo + Redirection d\'URL (youtube.com/redirect) est utilisée lors de l\'ouverture de liens dans les descriptions de vidéos + Contournement des redirections URL (youtube.com/redirect) lors de l’ouverture de liens dans les descriptions de vidéo + Activer les liens ouverts directement + Les commandes de balayage sont désactivés + Les commandes de balayage sont activés + Activer les commandes de balayage + Option pour le dpi pour utiliser certains agencements de téléphone + Activer la mise en page téléphone + Le tapotage de la barre de recherche est désactivé + N’enregistre pas les valeurs de qualité vidéo même lorsque la qualité vidéo est modifiée + Enregistre la valeur de qualité vidéo chaque fois que vous modifiez la qualité vidéo + Activer l\'enregistrement de la qualité de la vidéo + Le tapotage de la barre de recherche est activé + Activer le tapotage de la barre de recherche + Même si la luminosité est réglée à 0 par balayage, la luminosité automatique n\'est pas activée + Lorsque la luminosité atteint 0 par balayage, la luminosité automatique est activée + Activer la luminosité automatique en balayant + Le balayage de la luminosité est désactivé + Le balayage de la luminosité est activé + Activer le geste de luminosité + Le balayage rétroaction haptique est désactivée + Le balayage rétroaction haptique est activée + Activer le balayage rétroaction haptique + Le balayage du volume est désactivé + Le balayage du volume est activé + Activer le geste de volume + Le mini-lecteur pour tablette est désactivé + Le mini-lecteur pour tablette est activé + Activer le mini-lecteur pour tablette + Option pour utiliser certains agencements de tablette + Activer la mise en page tablette + La barre de recherche large est désactivée + La barre de recherche large est activée + Activer la barre de recherche large + Options expérimentales + Signaler des problèmes ou laisser des suggestions ici + Centre de problèmes de l\'Extension ReVanced + Paramètres de l\'Extension ReVanced + Réglages supplémentaires de l\'Extension + Paramètres de l\'Extension + Corriger les problèmes de tampon de lecture vidéo désactivés + Corriger les problèmes de tampon de lecture vidéo activés + Corriger les problèmes de tampon de lecture vidéo + Les sous-titres sont activés lors de la lecture d’une vidéo avec le sous-titrage + "Les sous-titres sont désactivés lors de la lecture d’une vidéo avec le sous-titrage" + Cacher les sous-titres automatiques + Les fenêtres pop-up du lecteur automatique sont affichées + Les fenêtres pop-up du lecteur automatique sont cachées + Cacher les fenêtres pop-up du lecteur automatique + Le bouton de lecture automatique est affiché + Le bouton de lecture automatique est caché + Cacher le bouton de lecture automatique + Cache le composant du conteneur de boutons + Cacher le composant conteneur de bouton + Le bouton Clip est affiché + Le bouton de Clip est caché + Cacher le bouton Clip + Le bouton Créer Shorts est affiché + Le bouton Créer Shorts est caché + Cacher le bouton Créer Shorts + Le bouton \"Je n\'aime pas\" est affiché + Le bouton \"Je n\'aime pas\" est caché + Cacher le bouton \"Je n\'aime pas\" + Le bouton de Téléchargement est affiché + Le bouton de Téléchargement est caché + Cacher le bouton de Téléchargement + Le bouton \"J\'aime\" est affiché + Le bouton \"J\'aime\" est caché + Cacher le bouton \"J\'aime\" + Le bouton de Chat en direct est affiché + Le bouton de Chat en direct est caché + Cacher le bouton de Chat en direct + Le bouton de la Playlist est affiché + Le bouton de la Playlist est caché + Cacher le bouton de la Playlist + Le bouton Signaler est affiché + Le bouton Signaler est caché + Cacher le bouton Signaler + Le bouton Partager est affiché + Le bouton Partager est caché + Cacher le bouton Partager + Le bouton de Remerciement est affiché + Le bouton de Remerciement est caché + Cacher le bouton de Remerciements + Le bouton des Sous-titres est affiché + Le bouton des Sous-titres est caché + Cacher le bouton des Sous-titres + Le bouton de Cast est affiché + Le bouton de Cast est caché + Cacher le bouton de Cast + Le filigrane vidéo est affiché + Le filigrane vidéo est caché + Cacher le filigrane de la chaîne + Masque la section des commentaires ou le composant + Cacher le composant de commentaire + La section commentaires est est affiché + La section commentaires est caché + Cacher la section des commentaires + Le bouton Créer est affiché + Le bouton Créer est caché + Masquer le bouton Créer + La boîte de financement participatif est affichée + La boîte de financement participatif est cachée + Cacher la boîte de financement participatif + L\'adresse e-mail est affichée + L\'adresse e-mail est cachée + Cacher l\'adresse e-mail + Les cartes de l’écran de fin sont affichées + Les cartes de l’écran de fin sont cachées + Cacher les superpositions d’écran de fin + Le conteneur de bouton plein écran est affiché + Le conteneur de bouton plein écran est caché + Cacher le conteneur du bouton plein écran + Les cartes d’information sont affichés + Les cartes d’information sont cachées + Cacher les infos + Le mode Ambiant est affiché + Le mode Ambiant est caché + Cacher le mode Ambiant + Le menu de la piste audio est affiché + Le menu de la piste audio est caché + Cacher le menu de la piste audio + Le menu des sous-titres est affiché + Le menu des sous-titres est caché + Cacher le menu des sous-titres + Le menu d\'aide & commentaires est affiché + Le menu d\'aide & commentaires est caché + Cacher le menu d\'aide & commentaires + Le menu des contrôles d\'écoute est affiché + Le menu des contrôles d\'écoute est caché + Cacher le menu de contrôle d\'écoute + Écouter avec le menu YouTube Music est affiché + Écouter avec le menu YouTube Music est caché + Cacher l\'écoute avec le menu YouTube Music + Le menu vidéo en boucle est affiché + Le menu vidéo en boucle est caché + Cacher le menu vidéo en boucle + Plus d\'informations sur le menu est affiché + Plus d\'informations sur le menu est caché + Cacher le menu plus d’informations + La page de signalement est affichée + La page de signalement est cachée + Cacher la page de signalement + Le menu des statistiques pour les \"nerds\" est affiché + Le menu des statistiques pour les \"nerds\" est caché + Cacher le menu de statistique pour les \"nerds\" + Le menu regarder en VR (Réalité virtuelle) est affiché + Le menu regarder en VR (Réalité virtuelle) est caché + Cacher le menu \"Regarder en VR\" (Réalité virtuelle) + La playlist Mix est affichée + La playlist Mix est cachée + Cacher la playlist Mix + Le filtre de superposition du lecteur est affiché + Le filtre de superposition du lecteur est caché + Cacher le filtre de superposition du lecteur + L\'aperçu du commentaire affiché + L\'aperçu du commentaire caché + Cacher l\'aperçu du commentaire + Le bouton Shorts est affiché + Le bouton Shorts est caché + Cacher le bouton Shorts + Cache la section Shorts ou le composant du lecteur Shorts + Cacher le composant de Shorts + Le bouton de commentaires du lecteur Shorts est affiché + Le bouton des commentaires du lecteur Shorts est caché + Cacher les commentaires du lecteur Shorts + Cacher le composant du lecteur Shorts + Le bouton de remix du lecteur Shorts est affiché + Le bouton de remix du lecteur Shorts est caché + Cacher le bouton de remix sur le lecteur Shorts + Le bouton d\'abonnement sur le lecteur Shorts est affiché + Le bouton d\'abonnement sur le lecteur Shorts est caché + Cacher le bouton d\'abonnement sur le lecteur Shorts + Le bouton de remerciement sur le lecteur Shorts est affiché + Le bouton de remerciement sur le lecteur Shorts est caché + Cacher le bouton de remerciement sur le lecteur Shorts + Les étagères des Shorts sont affichées + Les étagères des Shorts sont cachées + Cacher l\'étagère de Shorts + Le lecteur Shorts est désactivé au démarrage de l\'application + Le lecteur Shorts est activé au démarrage de l\'application + Lecteur de Shorts au démarrage de l\'application + Les étagères des stories sont affichées + Les étagères des stories sont cachées + Cacher l\'étagère de Stories + Les actions suggérées sont affichées + Les actions suggérées sont cachées + Cacher les actions suggérées + Le temps et la barre de recherche sont affichés + Le temps et la barre de recherche sont cachés + Le temps et la barre de recherche + Paramètres de disposition du lecteur inférieur + Paramètres de disposition du menu contextuel + Paramètres de mise en page plein écran + Paramètres généraux de mise en page + Paramètres de disposition du lecteur + Paramètres de disposition de la barre de recherche + Paramètres liés à la disposition + Paramètres de mise en page + Divers Paramètres + Autre Paramètres + Autres + Le bouton de répétition automatique est caché + Le bouton de répétition automatique est affiché + Afficher le bouton de répétition automatique + Le bouton Copier le lien est caché + Le bouton Copier le lien est affiché + Afficher le bouton de copie du lien + Le bouton Copier le lien avec horodatage est caché + Le bouton Copier le lien avec horodatage est affiché + Afficher le bouton de copie du lien avec horodatage + Le bouton de téléchargement est caché + Le bouton de téléchargement est affiché + Afficher le bouton de téléchargement + Paramètres liés au bouton de superposition + Paramètres du bouton de superposition + Le bouton de la liste blanche est caché + Le bouton de la liste blanche est affiché + Afficher le bouton de la liste blanche + Icône actuel : Icône YT par défaut + Icône actuel : Icône YT Premium + Icône YT Premium + Informations sur les correctifs appliqués + Informations sur les correctifs + Cache le composant des paramètres du lecteur du panneau de vol + Composant du panneau de survol du lecteur + "Comme il s’agit toujours d’un élément expérimental, il peut y avoir d’autres questions inconnues. Êtes-vous sûr de vouloir continuer?" + "Passe la version client YouTube à v17.28.35 pour charger l’ancienne mise en page Dans les paramètres de l’application, la version YouTube peut être marquée comme v17.28.35" + "Aide le dpi à modifier certaines dispositions de téléphone. Si vous activez ce paramètre, les fonctionnalités suivantes sont disponibles: + + - Publications communautaires + - Masquer la liste de lecture Mix" + "Correction des problèmes de mémoire tampon de lecture vidéo dans certaines régions. Si vous activez ce paramètre, le problème suivant peut survenir : + + - Lors de la lecture d’une vidéo dans la liste de lecture, le problème peut ne pas être résolu" + "Permet de modifier certaines mises en page pour les tablettes. Si vous activez ce paramètre, les fonctionnalités suivantes ne sont pas disponibles : + + - Mode ambiant + - Publications communautaires" + Les données qui ne sont pas similaires sont fournies par l\'API Worker True RYD. Appuyez ici pour en savoir plus. + true-ryd.cane.workers.dev + L\'API miroir est désactivée + L\'API miroir est activée + Activer l\'API Miroir + "True RYD Worker API utilise le nombre d’aversions exposé dans l’API YouTube Endpoint. + +Activez cette option uniquement pour ceux qui rencontrent des problèmes lors de l’utilisation de l’API RYD par défaut. + +Vous voulez continuer ?" + True RYD Worker + Les données qui ne sont pas similaires sont fournies par l\'API Worker True RYD. Appuyez ici pour en savoir plus. + ReturnYouTubeDislike.com + Les dislikes sont affichées sous forme de nombre + Les dislikes sont affichés sous forme de pourcentage + Dislikes en pourcentage + Les dislikes ne sont pas affichés + Les dislikes sont affichées + Retour YouTube Dislike + Les dislikes ne sont disponible (limite de clients d\'API atteinte) + RetourYouTubeDislike n\'a pas réussi à confirmer le nouvel utilisateur + RetourYouTubeDislike a échoué à confirmer le vote + Les dislikes sont temporairement indisponible (temporisation de l’API) + RetourYouTubeDislike n\'a pas pu s\'inscrire en tant que nouvel utilisateur + RetourYouTubeDislike a échoué à envoyer le vote + Paramètres pour le retour du nombre de gens qui ont mis \"Je n\'aimes pas\" + Retour YouTube Dislike + Paramètres ReVanced + Paramètres liés aux contrôles par balayage + Paramètres des contrôles de balayage + La quantité de seuil pour que le balayage se produise + Seuil de magnitude de balayage + La visibilité de l’arrière-plan de superposition par balayage + Visibilité de l\'arrière-plan en balayage + La taille du texte pour la superposition par balayage + Taille du texte superposé + La quantité de millisecondes pendant laquelle la superposition est visible + Délai de superposition + Outil utilisé + Les annonces vidéo sont affichées + Les annonces vidéo sont cachées + Cacher les annonces vidéo + Impossible de définir la qualité + Pas de connexion internet + Changer la qualité des données mobiles par défaut en: + Impossible de modifier la qualité des données mobiles par défaut + Changer la qualité Wi-Fi par défaut pour: + Impossible de modifier la qualité WI-FI par défaut + Paramètres liés à la vidéo + Paramètres vidéo + Échec d’ajout de chaîne %s à la liste blanche %s + La chaîne %s a été ajoutée à la liste blanche %s + Annonces vidéo + Publicités + Nom de la chaîne + Il n\'y a pas de chaînes sur la liste blanche + Non ajouté à la liste blanche + Ajouté à la liste blanche + Liste blanche des chaînes + Impossible de récupérer les détails du canal, code reçu %d + Redémarrer pour appliquer les paramètres de la liste blanche des canaux + Impossible de retirer la chaîne %s de la liste blanche %s + La chaîne %s a été retirée de la liste blanche %s + Vérifier ou supprimer la liste des chaînes ajoutés à la liste blanche + Paramètres de la liste blanche + Vitesse de la vidéo + Vitesse + SponsorBlock + SB + Le serveur Sponsorblock ne répond pas! + Déjà lu + "Il est recommandé de lire les directives SponsorBlock avant de soumettre un moment" + Me montrer + Il existe des lignes directrices + Les directives contiennent des conseils et des règles sur la soumission de moments + Afficher les directives + Paramètres SponsorBlock + Paramètres liés au SponsorBlock + Basculé avec succès. Recharger la vidéo + Passage du serveur API miroir au serveur API principal.. + Écrans de fin/Crédits + Crédits ou lorsque les cartes de fin YouTube apparaissent. (Pas pour les conclusions orales) + Tangente de fillers/blagues + Scènes tangentielles ajoutées uniquement pour les fillers ou l’humour qui ne sont pas nécessaires pour comprendre le contenu principal de la vidéo. Cela ne devrait pas inclure de détails contextuels ou contextuels. + Animation d’entracte/intro + Un intervalle sans contenu réel. Pourrait être une pause, image statique, animation répétée + Musique : Section non musicale + Réservé à l’utilisation dans les vidéoclips. Cela comprend les introductions ou les outros dans les vidéoclips + Aperçu/Récapitulatif + "Récapitulation des épisodes précédents, ou un aperçu de ce qui est à venir plus tard dans la vidéo actuelle ou les vidéos à venir dans la même série. Destiné aux clips montés ensemble qui ne fournissent pas d’informations supplémentaires." + Non rémunéré/auto-promotion + Lorsqu’il y a des activités de promotion non rémunérées ou d’autopromotion, y compris des sections précises sur les marchandises, les dons ou les renseignements sur les personnes avec lesquelles ils ont collaboré. + Sponsor + Promotion payée, recommandations payées et publicités directes + Rappel d\'interaction (S\'abonner) + Lorsqu’il y a un court rappel d’aimer, de s’abonner ou de les suivre au milieu du contenu + Échec de l\'exportation des paramètres + Paramètres Importer/Exporter + Il s’agit de votre configuration complète qui est applicable dans l’extension de bureau dans JSON. Cela comprend votre code d’utilisateur, alors assurez-vous de le partager judicieusement. + Échec de l\'importation des paramètres + Les paramètres ont été importés avec succès + Passer automatiquement + Passer automatiquement une fois + "Ne pas passer" + Affiché un bouton de saut (passer le moment) + Passer le moment + L\'outro a été passée + Le filler a été passée + L\'intro a été passée + Le moment ennuyeux de la musique a été passée + L\'apperçu a été passée + Le moment du sponsor a été passée + L\'auto-promo a été passée + Le sponsor a été passée + Le moment ennuyeux a été passée + Le moment non désirée a été passée + Statistiques + Chargement.. + "\"Vous avez sauvé des gens de <b>%s</b> moments." + "Cela représente <b>%s</b> de leur vie. Cliquez pour voir le tableau des leaders." + SponsorBlock est désactivé + "Vous avez passer <b>%s</b> moments." + "Cela fait <b>%s</b>." + Soumission: <b>%s</b> + Ton nom d\'utilisateur: <b>%s</b> + Clique pour changer ton nom d\'utilisateur + Impossible de changer le nom d’utilisateur (erreur inconnue) : État: %d %s + Nom d\'utilisateur changer avec succès + "Je ne peux pas soumettre le moment. +(Existe déjà)" + "Je ne peux pas soumettre le moment (interdit). + +%s" + "Je ne peux pas soumettre le nom d'utilisateur. +Limite atteinte (Trop d’utilisateurs ou d’adresses IP)" + Impossible de soumettre le moment : %s + Impossible de soumettre les moments (erreur): État: %d %s + Soumission du moment… + Moment soumis avec succès + Taper pour passer + Changement de catégorie + Voter contre + "Impossible de voter pour le moment + +%s" + "Impossible de voter pour le moment +Limite atteinte(Trop d'utilisateurs de même utilisateur ou de la même adresse IP)" + Impossible de voter pour le moment : État: %d %s + Il n\'y a pas de moments pour lesquels voter + Voter pour le moment… + Voter avec succès + Voter pour + diff --git a/src/main/resources/youtube/translations/id-rID/strings.xml b/src/main/resources/youtube/translations/id-rID/strings.xml new file mode 100644 index 000000000..abc91b01f --- /dev/null +++ b/src/main/resources/youtube/translations/id-rID/strings.xml @@ -0,0 +1,618 @@ + + + Tentang Aplikasi + Aplikasi ini menggunakan API dari SponsorBlock + Tekan untuk mempelajari lebih lanjut, dan lihat unduhan untuk platform lain di: sponsor.ajay.app + Integrasi dibuat oleh JakubWeg + Aktifkan kontrol aksesibilitas untuk pemutar video? + Kontrol anda diubah karena layanan aksesibilitas aktif. + URL API diubah + URL API yang disediakan tidak valid + URL API diatur ulang + URL API MIRROR diubah + URL API MIRROR tersebut tidak valid + URL API MIRROR diatur ulang + Apakah anda ingin mengubah warnanya? + "Anda sekarang dapat mengubah kategori warnanya dengan menekan diatas ini." + Warna diubah + Kode hex tidak valid + Atur ulang warna + Apa yang harus dilakukan dengan segmen yang berbeda + Aktifkan SponsorBlock + SponsorBlock adalah sistem crowd-source untuk melewatkan bagian yang mengganggu di video YouTube + Aktifkan SponsorBlock Mirror + Saat server API SponsorBlock sedang down, alihkan server API mirror ke server API default + Aktifkan penambahan segmen baru + Aktifkan ini untuk mengaktifkan penambahan segmen eksperimental (memiliki masalah visibilitas tombol) + Aktifkan voting + Aktifkan ini untuk mengaktifkan voting. + Umum + Menyesuaikan langkah segmen baru + Ini adalah jumlah milidetik yang dapat anda pindahkan saat anda menggunakan tombol penyesuaian waktu sambil menambahkan segmen baru + Ubah URL API + "URL yang digunakan SponsorBlock untuk melakukan panggilan ke server. <b>Jangan ubah ini kecuali anda tahu apa yang anda lakukan.</b>" + Ubah URL API Mirror + "URL server mirror untuk beralih ketika server SponsorBlock sedang down. <b>Jangan ubah ini kecuali anda tahu apa yang anda lakukan.</b>" + Durasi segmen minimum + Segmen yang lebih pendek dari nilai yang ditetapkan (dalam detik) tidak akan dilewati atau ditampilkan di pemutar + Lewati pelacakan hitungan + Hal ini memungkinkan sistem leaderboard SponsorBlock tahu berapa banyak waktu orang telah disimpan. Ekstensi mengirim pesan ke server setiap kali anda melewatkan segmen + Tampilkan notifikasi ketika melewatkan segmen otomatis + Tekan untuk melihat contoh notifikasi + Tampilkan waktu tanpa segmen + Waktu ini muncul dalam tanda kurung di sebelah waktu saat ini. Ini menunjukkan total durasi video dikurangi segmen apa pun. + ID pengguna pribadi anda + Ini harus dirahasiakan. Ini seperti kata sandi dan tidak boleh dibagikan dengan siapa pun. Jika seseorang memiliki ini, mereka dapat meniru anda + Silahkan instal MicroG + MicroG tidak ditemukan + Pengaturan notifikasi + "1. Pendaftaran perangkat Google dan Cloud Messaging harus diaktifkan untuk pemberitahuan. +2. ReVanced perlu ditampilkan sebagai terdaftar di bawah Cloud Messaging. +3. Status saat ini dalam Cloud Messaging harus terhubung." + Pengaturan MicroG + menit + Pilih kategori segmen + "Segmen berlangsung dari %02d:%02d hingga %02d:%02d (%d menit %02d detik) +Apakah sudah siap untuk dikirim?" + Apakah waktunya sudah benar? + "Anda telah menonaktifkan kategori ini dalam pengaturan, aktifkan untuk dapat mengirimkan" + Apakah anda ingin mengedit waktu untuk awal atau akhir segmen? + Waktu tidak valid diberikan + Selesai + Edit waktu segmen secara manual + akhir + Tandai dua lokasi di bilah waktu terlebih dahulu + mulai + Atur %02d:%02d:%04d sebagai awal atau akhir segmen baru? + sekarang + Waktu segmen berakhir pada + Akhir set segmen + Waktu segmen dimulai pada + Awal set segmen + Segmen SponsorBlock baru + Atur ulang + Pengaturan terkait iklan + Pengaturan iklan + Kartu album ditampilkan dari hasil pencarian + Kartu album disembunyikan dari hasil pencarian + Sembunyikan kartu album + Rak breaking news ditampilkan + Rak breaking news disembunyikan + Sembunyikan rak breaking news + Iklan tombol ditampilkan + Iklan tombol disembunyikan + Sembunyikan iklan tombol + Pedoman channel ditampilkan + Pedoman channel disembunyikan + Sembunyikan pedoman channel + Teaser chapter ditampilkan + Teaser chapter disembunyikan + Sembunyikan teaser chapter dibawah video + Pedoman komunitas ditampilkan + Pedoman komunitas disembunyikan + Sembunyikan pedoman komunitas + Postingan komunitas ditampilkan + Postingan komunitas disembunyikan + Sembunyikan postingan komunitas + Spanduk compact ditampilkan + Spanduk compact disembunyikan + Sembunyikan spanduk compact + Filter komponen dengan nama mereka dipisahkan dengan koma + Filter kustom + Kotak darurat ditampilkan + Kotak darurat disembunyikan + Sembunyikan kotak darurat + Iklan umum ditampilkan + Iklan umum disembunyikan + Sembunyikan iklan umum + Rak gambar ditampilkan + Rak gambar disembunyikan + Sembunyikan rak gambar + Panel informasi ditampilkan + Panel informasi disembunyikan + Sembunyikan panel informasi + Survei feed ditampilkan + Survei feed disembunyikan + Sembunyikan survei feed + Postingan terbaru ditampilkan + Postingan terbaru disembunyikan + Sembunyikan postingan terbaru + Panel medis ditampilkan + Panel medis disembunyikan + Sembunyikan panel medis + Spanduk merchandise ditampilkan + Spanduk merchandise disembunyikan + Sembunyikan spanduk merchandise + Rak film ditampilkan + Rak film disembunyikan + Sembunyikan rak film + Kartu resmi ditampilkan dari hasil pencarian + Kartu resmi disembunyikan dari hasil pencarian + Sembunyikan kartu resmi + Konten berbayar ditampilkan + Konten berbayar disembunyikan + Sembunyikan konten berbayar + Kartu sponsor pribadi ditampilkan + Kartu sponsor pribadi disembunyikan + Sembunyikan kartu sponsor pribadi + Pemisah abu-abu ditampilkan + Pemisah abu-abu disembunyikan + Sembunyikan pemisah abu-abu + Suggestions ditampilkan + Suggestions disembunyikan + Sembunyikan suggestions + Timed reactions ditampilkan + Timed reactions disembunyikan + Sembunyikan timed reactions + Filter user dinonaktifkan + Filter user diaktifkan + Aktifkan filter user + Spanduk lihat produk ditampilkan + Spanduk lihat produk disembunyikan + Sembunyikan spanduk lihat produk + Panel pencarian web ditampilkan + Panel pencarian web disembunyikan + Sembunyikan panel pencarian web + Durasi maksimum media yang pemutar akan coba untuk buffer + Ukuran buffer maksimum + Durasi media yang harus dibuffer untuk memulai atau melanjutkan pemutaran setelah tindakan user seperti mencari + Ukuran buffer awal pemutaran + Durasi media yang harus dibuffer agar pemutaran dilanjutkan setelah buffering ulang + Ukuran buffer ulang + Pengaturan terkait ukuran buffer video + Pengaturan buffer video + Pilih resolusi video default di jaringan seluler + Kualitas video default seluler + Pilih resolusi video default di jaringan Wi-Fi + Kualitas video default Wi-Fi + Pilih kecepatan video default + Kecepatan video default + tidak diinstal. Silakan instal. + "Nama paket aplikasi downloader seperti New Pipe atau PowerTube" + Nama paket aplikasi downloader + Pengaturan terkait downloader default + Pengaturan downloader + Overlay endscreen ditampilkan + Overlay endscreen disembunyikan + Sembunyikan overlay endscreen + Overlay strip film ditampilkan + Overlay strip film disembunyikan + Sembunyikan overlay strip film + Swipe feedback haptic diaktifkan + Swipe feedback haptic dinonaktifkan + Nonaktifkan swipe feedback haptic + Mencari feedback haptic diaktifkan + Mencari feedback haptic dinonaktifkan + Nonaktifkan mencari feedback haptic + Feedback haptic chapter diaktifkan + Feedback haptic chapter dinonaktifkan + Nonaktifkan feedback haptic chapter + Nonaktifkan feedback haptic pada saat menekan lama + Nonaktifkan feedback haptic + Feedback haptic zoom diaktifkan + Feedback haptic zoom dinonaktifkan + Nonaktifkan feedback haptic zoom + Timestamp dicopy ke clipboard + Always auto repeat dinonaktifkan + Always auto repeat diaktifkan + Always auto repeat + Nonaktifkan gestur swipe saat kontrol pemutar terlihat + Aktifkan selalu gestur swipe terlepas dari kontrol pemutar yang terlihat atau tidak + Aktifkan selalu gestur swipe + Kecepatan video kustom dinonaktifkan + Kecepatan video kustom diaktifkan + Aktifkan kecepatan video kustom + Browser eksternal dinonaktifkan + Browser eksternal diaktifkan + Aktifkan browser eksternal + Brightness HDR otomatis dinonaktifkan + Brightness HDR otomatis diaktifkan + Aktifkan brightness HDR otomatis + Pemutar video minimalis dinonaktifkan + Pemutar video minimalis diaktifkan + Aktifkan pemutar video minimalis + Layout YouTube akan mengikuti status akun Google anda + Trik versi YouTube untuk memaksa mengaktifkan layout lama + Aktifkan layout lama + Pengaturan layout kualitas baru ditampilkan + Pengaturan layout kualitas lama ditampilkan + Aktifkan layout kualitas lama + Pengalihan URL (youtube.com/redirect) digunakan saat membuka link dalam deskripsi video + Bypass pengalihan URL (youtube.com/redirect) saat membuka link di deskripsi video + Aktifkan link terbuka secara langsung + Tekan untuk swipe dinonaktifkan + Tekan untuk swipe diaktifkan + Aktifkan gestur tekan untuk swipe + Trik dpi untuk menggunakan beberapa layout ponsel + Aktifkan layout ponsel + Tapping seekbar dinonaktifkan + Tidak menyimpan nilai kualitas video bahkan saat mengubah kualitas video + Simpan nilai kualitas video setiap kali anda mengubah kualitas video + Aktifkan simpan kualitas video + Tapping seekbar diaktifkan + Aktifkan tapping seekbar + Bahkan jika brightness diatur ke 0 dengan swiping, brightness otomatis dinonaktifkan + Saat brightness mencapai 0 dengan swiping, brightness otomatis diaktifkan + Aktifkan brightness otomatis dengan swiping + Swipe brightness dinonaktifkan + Swipe brightness dinonaktifkan + Aktifkan gestur brightness + Feedback haptic tekan untuk swipe dinonaktifkan + Feedback haptic tekan untuk swipe diaktifkan + Aktifkan feedback haptic tekan untuk swipe + Swipe volume dinonaktifkan + Swipe volume diaktifkan + Aktifkan gestur volume + Tablet mini-player dinonaktifkan + Tablet mini-player diaktifkan + Aktifkan tablet mini-player + Trik dpi untuk menggunakan beberapa layout tablet + Aktifkan layout tablet + Search bar lebar dinonaktifkan + Search bar lebar diaktifkan + Aktifkan search bar lebar + Pengaturan eksperimental + Laporkan masalah atau tinggalkan saran di sini + Pusat masalah ReVanced Extended + Pengaturan ReVanced Extended + Pengaturan terkait Extended + Pengaturan Extended + Perbaiki masalah buffer pemutaran video dinonaktifkan + Perbaiki masalah buffer pemutaran video diaktifkan + Perbaiki masalah buffer pemutaran video + Captions diaktifkan saat memutar video dengan captions diterapkan + "Captions tidak diaktifkan saat memutar video dengan captions diterapkan" + Sembunyikan captions otomatis + Panel popup auto pemutar ditampilkan + Panel popup auto pemutar disembunyikan + Sembunyikan panel popup auto pemutar + Tombol autoplay ditampilkan + Tombol autoplay disembunyikan + Sembunyikan tombol autoplay + Menyembunyikan komponen wadah tombol + Sembunyikan komponen wadah tombol + Tombol clip ditampilkan + Tombol clip disembunyikan + Sembunyikan tombol clip + Tombol buat shorts ditampilkan + Tombol buat shorts disembunyikan + Sembunyikan tombol buat shorts + Tombol dislike ditampilkan + Tombol dislike disembunyikan + Sembunyikan tombol dislike + Tombol download ditampilkan + Tombol download disembunyikan + Sembunyikan tombol download + Tombol like ditampilkan + Tombol like disembunyikan + Sembunyikan tombol like + Tombol live chat ditampilkan + Tombol live chat disembunyikan + Sembunyikan tombol live chat + Tombol playlist ditampilkan + Tombol playlist disembunyikan + Sembunyikan tombol playlist + Tombol report ditampilkan + Tombol report disembunyikan + Sembunyikan tombol report + Tombol share ditampilkan + Tombol share disembunyikan + Sembunyikan tombol share + Tombol thanks ditampilkan + Tombol thanks disembunyikan + Sembunyikan tombol thanks + Tombol captions ditampilkan + Tombol captions disembunyikan + Sembunyikan tombol captions + Tombol cast ditampilkan + Tombol cast disembunyikan + Sembunyikan tombol cast + Watermark channel ditampilkan + Watermark channel disembunyikan + Sembunyikan watermark channel + Sembunyikan bagian komentar atau komponen + Sembunyikan komponen komentar + Bagian komentar ditampilkan + Bagian komentar disembunyikan + Sembunyikan bagian komentar + Tombol buat ditampilkan + Tombol buat disembunyikan + Sembunyikan tombol buat + Kotak crowdfunding ditampilkan + Kotak crowdfunding disembunyikan + Sembunyikan kotak crowdfunding + Alamat email ditampilkan + Alamat email disembunyikan + Sembunyikan alamat email + Kartu endscreen ditampilkan + Kartu endscreen disembunyikan + Sembunyikan kartu endscreen + Wadah tombol fullscreen ditampilkan + Wadah tombol fullscreen disembunyikan + Sembunyikan wadah tombol fullscreen + Kartu info ditampilkan + Kartu info disembunyikan + Sembunyikan kartu info + Menu mode ambient ditampilkan + Menu mode ambient disembunyikan + Sembunyikan menu mode ambient + Menu track audio ditampilkan + Menu track audio disembunyikan + Sembunyikan menu track audio + Menu captions ditampilkan + Menu captions disembunyikan + Sembunyikan menu captions + Menu & bantuan feedback ditampilkan + Menu & bantuan feedback disembunyikan + Sembunyikan menu & bantuan feedback + Menu kontrol listening ditampilkan + Menu kontrol listening disembunyikan + Sembunyikan menu kontrol listening + Menu dengarkan dengan YouTube Music ditampilkan + Menu dengarkan dengan YouTube Music disembunyikan + Sembunyikan menu dengarkan dengan YouTube Music + Menu video loop ditampilkan + Menu video loop disembunyikan + Sembunyikan menu video loop + Menu informasi lainnya ditampilkan + Menu informasi lainnya disembunyikan + Sembunyikan menu informasi lainnya + Menu report ditampilkan + Menu report disembunyikan + Sembunyikan menu report + Statistik untuk menu nerds ditampilkan + Statistik untuk menu nerds disembunyikan + Sembunyikan statistik untuk menu nerds + Menu tonton di VR ditampilkan + Menu tonton di VR disembunyikan + Sembunyikan menu tonton di VR + Playlist mix ditampilkan + Playlist mix disembunyikan + Sembunyikan playlist mix + Filter overlay pemutar ditampilkan + Filter overlay pemutar disembunyikan + Sembunyikan filter overlay pemutar + Komentar preview ditampilkan + Komentar preview disembunyikan + Sembunyikan komentar preview + Tombol shorts ditampilkan + Tombol shorts disembunyikan + Sembunyikan tombol shorts + Sembunyikan bagian shorts atau komponen pemutar shorts + Sembunyikan komponen shorts + Tombol komentar di pemutar shorts ditampilkan + Tombol komentar di pemutar shorts disembunyikan + Sembunyikan tombol komentar di pemutar shorts + Sembunyikan komponen pemutar shorts + Tombol remix di pemutar shorts ditampilkan + Tombol remix di pemutar shorts disembunyikan + Sembunyikan tombol remix di pemutar shorts + Tombol subscriptions di pemutar shorts ditampilkan + Tombol subscriptions di pemutar shorts disembunyikan + Sembunyikan tombol subscriptions di pemutar shorts + Tombol thanks di pemutar shorts ditampilkan + Tombol thanks di pemutar shorts disembunyikan + Sembunyikan tombol thanks di pemutar shorts + Rak shorts ditampilkan + Rak shorts disembunyikan + Sembunyikan rak shorts + Pemutar shorts dinonaktifkan saat memulai aplikasi + Pemutar shorts diaktifkan saat memulai aplikasi + Pemutar shorts saat memulai aplikasi + Rak stories ditampilkan + Rak stories disembunyikan + Sembunyikan rak stories + Suggested actions ditampilkan + Suggested actions disembunyikan + Sembunyikan suggested actions + Waktu dan seekbar ditampilkan + Waktu dan seekbar disembunyikan + Sembunyikan waktu dan seekbar + Pengaturan layout bawah pemutar + Pengaturan layout menu flyout + Pengaturan layout fullscreen + Pengaturan tata letak umum + Pengaturan layout pemutar + Pengaturan layout seekbar + Pengaturan terkait layout + Pengaturan layout + Pengaturan terkait lainnya + Pengaturan lain-lain + Lainnya + Tombol auto repeat disembunyikan + Tombol auto repeat ditampilkan + Tampilkan tombol auto repeat + Tombol copy link disembunyikan + Tombol copy link ditampilkan + Tampilkan tombol copy link + Tombol copy link dengan timestamp disembunyikan + Tombol copy link dengan timestamp ditampilkan + Tampilkan tombol copy link dengan timestamp + Tombol download disembunyikan + Tombol download ditampilkan + Tampilkan tombol download + Pengaturan terkait tombol overlay + Pengaturan tombol overlay + Tombol whitelist disembunyikan + Tombol whitelist ditampilkan + Tampilkan tombol whitelist + Header terkini: Header default + Header terkini: Header premium + Header premium + Informasi tentang patch yang diterapkan + Informasi patch + Menyembunyikan komponen panel flyout pengaturan pemutar + Komponen panel flyout pemutar + "Karena ini masih merupakan fitur percobaan, mungkin ada masalah lain yang tidak diketahui. +Apakah anda yakin ingin melanjutkan?" + "Trik versi klien YouTube ke v17.28.35 untuk memuat layout lama + +Di pengaturan aplikasi, versi YouTube mungkin ditandai sebagai v17.28.35" + "Trik dpi untuk mengubah beberapa layout menjadi layout ponsel. + +Jika anda mengaktifkan pengaturan ini, fitur berikut akan tersedia: +- Postingan komunitas +- Sembunyikan playlist mix" + "Perbaiki masalah buffer pemutaran video di beberapa wilayah/negara. + +Jika anda mengaktifkan pengaturan ini, masalah berikut mungkin terjadi: +- Saat memutar video di playlist, masalah mungkin tidak dapat diperbaiki" + "Trik dpi untuk mengubah beberapa layout menjadi layout tablet. + +Jika anda mengaktifkan pengaturan ini, fitur berikut tidak tersedia: +- Mode ambient +- Postingan komunitas" + Data dislike disediakan oleh API True RYD Worker. Tekan disini untuk mempelajari lebih lanjut. + true-ryd.cane.workers.dev + API mirror dinonaktifkan + API mirror diaktifkan + Aktifkan API mirror + "True RYD Worker API menghilangkan pengajuan voting dan proses pendaftaran. +Dengan demikian, ini kurang tepat daripada API RYD default. + +Aktifkan opsi ini hanya untuk mereka yang mengalami masalah saat menggunakan API RYD default. + +Apakah anda ingin melanjutkan?" + True RYD Worker + Data dislike disediakan oleh API Return YouTube Dislike. Tekan di sini untuk mempelajari lebih lanjut. + ReturnYouTubeDislike.com + Dislike ditampilkan sebagai angka + Dislike ditampilkan sebagai persentase + Dislike sebagai persentase + Dislike tidak ditampilkan + Dislike ditampilkan + Return YouTube Dislike + Dislikes tidak tersedia (batas API client tercapai) + ReturnYouTubeDislike gagal mengonfirmasi user baru + ReturnYouTubeDislike gagal mengonfirmasi vote + Dislikes untuk sementara tidak tersedia (waktu API habis) + ReturnYouTubeDislike gagal mendaftar sebagai user baru + ReturnYouTubeDislike gagal mengonfirmasi vote + Pengaturan terkait Return YouTube Dislike + Return YouTube Dislike + Pengaturan ReVanced + Pengaturan terkait kontrol swipe + Pengaturan kontrol swipe + Jumlah ambang batas untuk swipe terjadi + Ambang besar swipe + Visibilitas background overlay swipe + Visibilitas background swipe + Ukuran teks untuk overlay swipe + Ukuran teks overlay swipe + Jumlah milidetik overlay terlihat + Batas waktu overlay swipe + alat yang digunakan + Iklan video ditampilkan + Iklan video disembunyikan + Sembunyikan iklan video + Gagal menyetel kualitas + Tidak ada koneksi internet + Mengubah kualitas data seluler default menjadi: + Gagal mengubah kualitas data seluler default + Mengubah kualitas Wi-Fi default menjadi: + Gagal mengubah kualitas WI-FI default + Pengaturan terkait video + Pengaturan video + Gagal menambahkan channel %s ke %s whitelist + Channel %s telah ditambahkan ke %s whitelist + Iklan video + Iklan + Nama channel + Tidak ada channel yang masuk whitelist + Tidak ditambahkan ke whitelist + Ditambahkan ke whitelist + Whitelist channel + Gagal mengambil detail channel, menerima kode %d + Reboot untuk menerapkan pengaturan whitelist channel + Gagal menghapus channel %s dari %s whitelist + Channel %s telah dihapus dari %s whitelist + Periksa atau hapus channel yang ditambahkan ke whitelist + Pengaturan whitelist + Kecepatan video + Kecepatan + SponsorBlock + SB + Server Sponsorblock tidak merespons! + Sudah dibaca + "Disarankan untuk membaca pedoman SponsorBlock sebelum mengirimkan segmen apa pun" + Tunjukkan padaku + Ada pedoman + Pedoman berisi tips dan aturan tentang mengirimkan segmen + Lihat pedoman + Pengaturan SponsorBlock + Pengaturan terkait SponsorBlock + Berhasil beralih. memuat ulang video + Mengalihkan server mirror API ke server API utama.. + Endcards/kredit + Kredit atau saat kartu akhir YouTube muncul. Bukan untuk kesimpulan yang diucapkan + Filler tangent/lelucon + Adegan tangensial ditambahkan hanya untuk filler atau humor yang tidak diperlukan untuk memahami isi utama video. Ini tidak boleh menyertakan konteks atau detail latar belakang + Intermission/animasi intro + Interval tanpa konten sebenarnya. Bisa berupa jeda, static frame, animasi berulang + Musik: bagian non-musik + Hanya untuk digunakan dalam video musik. Lewati bagian video yang tidak ada dalam official mixes + Preview/rekap + "Rekap episode sebelumnya, atau preview tentang apa yang akan muncul nanti di video saat ini atau video mendatang dalam serial yang sama. Klip tidak boleh memberikan informasi tambahan." + Promosi tidak dibayar/diri sendiri + Ketika ada promosi yang tidak dibayar atau promosi diri sendiri. Ini termasuk bagian khusus tentang merchandise, donasi, atau informasi tentang dengan siapa mereka bekerja sama + Sponsor + Promosi berbayar, referensi berbayar, dan iklan langsung + Pengingat interaksi (subscribe) + Ketika ada pengingat singkat untuk like, subscribe, follow, atau berinteraksi dengan mereka di platform gratis atau berbayar apa pun + Gagal mengekspor pengaturan + Pengaturan impor/ekspor + Ini adalah seluruh konfigurasi anda yang berlaku di ekstensi desktop di JSON. Ini termasuk userID pribadi anda, jadi pastikan untuk membagikannya dengan bijak. + Gagal mengimpor pengaturan + Pengaturan berhasil diimpor + Lewati secara otomatis + Lewati secara otomatis sekali + "Jangan lakukan apapun" + Tampilkan tombol lewati + Segmen dilewati + Outro dilewati + Filler dilewati + Intro dilewati + Melewatkan bagian non-musik + Preview dilewati + Melewatkan segmen sponsor + Melewatkan promosi diri + Sponsor dilewati + Pengingat yang mengganggu dilewati + Melewati segmen yang belum dikirim + Statistik + Loading.. + "Anda telah menyelamatkan orang-orang dari <b>%s</b> segmen." + "Itu <b>%s</b> hidup mereka. Tekan untuk melihat leaderboard" + SponsorBlock dinonaktifkan + "Anda telah melewatkan <b>%s</b> segmen." + "Itu <b>%s</b>." + Submissions: <b>%s</b> + Username anda: <b>%s</b> + Tekan untuk mengubah username anda + Tidak dapat mengubah username: Status: %d %s + Username berhasil diubah + "Tidak dapat mengirimkan segmen. +Sudah ada" + "Tidak dapat mengirimkan segmen. + +%s" + "Tidak dapat mengirimkan segmen. +Rate Limited (Terlalu banyak dari user atau IP yang sama)" + Tidak dapat mengirimkan segmen: %s + Tidak dapat memilih segmen: Status: %d %s + Mengirimkan segmen… + Segmen berhasil dikirim + Tekan untuk melewati + Ubah kategori + Downvote + "Tidak dapat memilih segmen. + +%s" + "Tidak dapat memilih segmen. +Rate Limited (Terlalu banyak dari user atau IP yang sama)" + Tidak dapat memilih segmen: Status: %d %s + Tidak ada segmen untuk dipilih + Voting untuk segmen… + Vote berhasil + Upvote + diff --git a/src/main/resources/youtube/translations/in/strings.xml b/src/main/resources/youtube/translations/in/strings.xml new file mode 100644 index 000000000..abc91b01f --- /dev/null +++ b/src/main/resources/youtube/translations/in/strings.xml @@ -0,0 +1,618 @@ + + + Tentang Aplikasi + Aplikasi ini menggunakan API dari SponsorBlock + Tekan untuk mempelajari lebih lanjut, dan lihat unduhan untuk platform lain di: sponsor.ajay.app + Integrasi dibuat oleh JakubWeg + Aktifkan kontrol aksesibilitas untuk pemutar video? + Kontrol anda diubah karena layanan aksesibilitas aktif. + URL API diubah + URL API yang disediakan tidak valid + URL API diatur ulang + URL API MIRROR diubah + URL API MIRROR tersebut tidak valid + URL API MIRROR diatur ulang + Apakah anda ingin mengubah warnanya? + "Anda sekarang dapat mengubah kategori warnanya dengan menekan diatas ini." + Warna diubah + Kode hex tidak valid + Atur ulang warna + Apa yang harus dilakukan dengan segmen yang berbeda + Aktifkan SponsorBlock + SponsorBlock adalah sistem crowd-source untuk melewatkan bagian yang mengganggu di video YouTube + Aktifkan SponsorBlock Mirror + Saat server API SponsorBlock sedang down, alihkan server API mirror ke server API default + Aktifkan penambahan segmen baru + Aktifkan ini untuk mengaktifkan penambahan segmen eksperimental (memiliki masalah visibilitas tombol) + Aktifkan voting + Aktifkan ini untuk mengaktifkan voting. + Umum + Menyesuaikan langkah segmen baru + Ini adalah jumlah milidetik yang dapat anda pindahkan saat anda menggunakan tombol penyesuaian waktu sambil menambahkan segmen baru + Ubah URL API + "URL yang digunakan SponsorBlock untuk melakukan panggilan ke server. <b>Jangan ubah ini kecuali anda tahu apa yang anda lakukan.</b>" + Ubah URL API Mirror + "URL server mirror untuk beralih ketika server SponsorBlock sedang down. <b>Jangan ubah ini kecuali anda tahu apa yang anda lakukan.</b>" + Durasi segmen minimum + Segmen yang lebih pendek dari nilai yang ditetapkan (dalam detik) tidak akan dilewati atau ditampilkan di pemutar + Lewati pelacakan hitungan + Hal ini memungkinkan sistem leaderboard SponsorBlock tahu berapa banyak waktu orang telah disimpan. Ekstensi mengirim pesan ke server setiap kali anda melewatkan segmen + Tampilkan notifikasi ketika melewatkan segmen otomatis + Tekan untuk melihat contoh notifikasi + Tampilkan waktu tanpa segmen + Waktu ini muncul dalam tanda kurung di sebelah waktu saat ini. Ini menunjukkan total durasi video dikurangi segmen apa pun. + ID pengguna pribadi anda + Ini harus dirahasiakan. Ini seperti kata sandi dan tidak boleh dibagikan dengan siapa pun. Jika seseorang memiliki ini, mereka dapat meniru anda + Silahkan instal MicroG + MicroG tidak ditemukan + Pengaturan notifikasi + "1. Pendaftaran perangkat Google dan Cloud Messaging harus diaktifkan untuk pemberitahuan. +2. ReVanced perlu ditampilkan sebagai terdaftar di bawah Cloud Messaging. +3. Status saat ini dalam Cloud Messaging harus terhubung." + Pengaturan MicroG + menit + Pilih kategori segmen + "Segmen berlangsung dari %02d:%02d hingga %02d:%02d (%d menit %02d detik) +Apakah sudah siap untuk dikirim?" + Apakah waktunya sudah benar? + "Anda telah menonaktifkan kategori ini dalam pengaturan, aktifkan untuk dapat mengirimkan" + Apakah anda ingin mengedit waktu untuk awal atau akhir segmen? + Waktu tidak valid diberikan + Selesai + Edit waktu segmen secara manual + akhir + Tandai dua lokasi di bilah waktu terlebih dahulu + mulai + Atur %02d:%02d:%04d sebagai awal atau akhir segmen baru? + sekarang + Waktu segmen berakhir pada + Akhir set segmen + Waktu segmen dimulai pada + Awal set segmen + Segmen SponsorBlock baru + Atur ulang + Pengaturan terkait iklan + Pengaturan iklan + Kartu album ditampilkan dari hasil pencarian + Kartu album disembunyikan dari hasil pencarian + Sembunyikan kartu album + Rak breaking news ditampilkan + Rak breaking news disembunyikan + Sembunyikan rak breaking news + Iklan tombol ditampilkan + Iklan tombol disembunyikan + Sembunyikan iklan tombol + Pedoman channel ditampilkan + Pedoman channel disembunyikan + Sembunyikan pedoman channel + Teaser chapter ditampilkan + Teaser chapter disembunyikan + Sembunyikan teaser chapter dibawah video + Pedoman komunitas ditampilkan + Pedoman komunitas disembunyikan + Sembunyikan pedoman komunitas + Postingan komunitas ditampilkan + Postingan komunitas disembunyikan + Sembunyikan postingan komunitas + Spanduk compact ditampilkan + Spanduk compact disembunyikan + Sembunyikan spanduk compact + Filter komponen dengan nama mereka dipisahkan dengan koma + Filter kustom + Kotak darurat ditampilkan + Kotak darurat disembunyikan + Sembunyikan kotak darurat + Iklan umum ditampilkan + Iklan umum disembunyikan + Sembunyikan iklan umum + Rak gambar ditampilkan + Rak gambar disembunyikan + Sembunyikan rak gambar + Panel informasi ditampilkan + Panel informasi disembunyikan + Sembunyikan panel informasi + Survei feed ditampilkan + Survei feed disembunyikan + Sembunyikan survei feed + Postingan terbaru ditampilkan + Postingan terbaru disembunyikan + Sembunyikan postingan terbaru + Panel medis ditampilkan + Panel medis disembunyikan + Sembunyikan panel medis + Spanduk merchandise ditampilkan + Spanduk merchandise disembunyikan + Sembunyikan spanduk merchandise + Rak film ditampilkan + Rak film disembunyikan + Sembunyikan rak film + Kartu resmi ditampilkan dari hasil pencarian + Kartu resmi disembunyikan dari hasil pencarian + Sembunyikan kartu resmi + Konten berbayar ditampilkan + Konten berbayar disembunyikan + Sembunyikan konten berbayar + Kartu sponsor pribadi ditampilkan + Kartu sponsor pribadi disembunyikan + Sembunyikan kartu sponsor pribadi + Pemisah abu-abu ditampilkan + Pemisah abu-abu disembunyikan + Sembunyikan pemisah abu-abu + Suggestions ditampilkan + Suggestions disembunyikan + Sembunyikan suggestions + Timed reactions ditampilkan + Timed reactions disembunyikan + Sembunyikan timed reactions + Filter user dinonaktifkan + Filter user diaktifkan + Aktifkan filter user + Spanduk lihat produk ditampilkan + Spanduk lihat produk disembunyikan + Sembunyikan spanduk lihat produk + Panel pencarian web ditampilkan + Panel pencarian web disembunyikan + Sembunyikan panel pencarian web + Durasi maksimum media yang pemutar akan coba untuk buffer + Ukuran buffer maksimum + Durasi media yang harus dibuffer untuk memulai atau melanjutkan pemutaran setelah tindakan user seperti mencari + Ukuran buffer awal pemutaran + Durasi media yang harus dibuffer agar pemutaran dilanjutkan setelah buffering ulang + Ukuran buffer ulang + Pengaturan terkait ukuran buffer video + Pengaturan buffer video + Pilih resolusi video default di jaringan seluler + Kualitas video default seluler + Pilih resolusi video default di jaringan Wi-Fi + Kualitas video default Wi-Fi + Pilih kecepatan video default + Kecepatan video default + tidak diinstal. Silakan instal. + "Nama paket aplikasi downloader seperti New Pipe atau PowerTube" + Nama paket aplikasi downloader + Pengaturan terkait downloader default + Pengaturan downloader + Overlay endscreen ditampilkan + Overlay endscreen disembunyikan + Sembunyikan overlay endscreen + Overlay strip film ditampilkan + Overlay strip film disembunyikan + Sembunyikan overlay strip film + Swipe feedback haptic diaktifkan + Swipe feedback haptic dinonaktifkan + Nonaktifkan swipe feedback haptic + Mencari feedback haptic diaktifkan + Mencari feedback haptic dinonaktifkan + Nonaktifkan mencari feedback haptic + Feedback haptic chapter diaktifkan + Feedback haptic chapter dinonaktifkan + Nonaktifkan feedback haptic chapter + Nonaktifkan feedback haptic pada saat menekan lama + Nonaktifkan feedback haptic + Feedback haptic zoom diaktifkan + Feedback haptic zoom dinonaktifkan + Nonaktifkan feedback haptic zoom + Timestamp dicopy ke clipboard + Always auto repeat dinonaktifkan + Always auto repeat diaktifkan + Always auto repeat + Nonaktifkan gestur swipe saat kontrol pemutar terlihat + Aktifkan selalu gestur swipe terlepas dari kontrol pemutar yang terlihat atau tidak + Aktifkan selalu gestur swipe + Kecepatan video kustom dinonaktifkan + Kecepatan video kustom diaktifkan + Aktifkan kecepatan video kustom + Browser eksternal dinonaktifkan + Browser eksternal diaktifkan + Aktifkan browser eksternal + Brightness HDR otomatis dinonaktifkan + Brightness HDR otomatis diaktifkan + Aktifkan brightness HDR otomatis + Pemutar video minimalis dinonaktifkan + Pemutar video minimalis diaktifkan + Aktifkan pemutar video minimalis + Layout YouTube akan mengikuti status akun Google anda + Trik versi YouTube untuk memaksa mengaktifkan layout lama + Aktifkan layout lama + Pengaturan layout kualitas baru ditampilkan + Pengaturan layout kualitas lama ditampilkan + Aktifkan layout kualitas lama + Pengalihan URL (youtube.com/redirect) digunakan saat membuka link dalam deskripsi video + Bypass pengalihan URL (youtube.com/redirect) saat membuka link di deskripsi video + Aktifkan link terbuka secara langsung + Tekan untuk swipe dinonaktifkan + Tekan untuk swipe diaktifkan + Aktifkan gestur tekan untuk swipe + Trik dpi untuk menggunakan beberapa layout ponsel + Aktifkan layout ponsel + Tapping seekbar dinonaktifkan + Tidak menyimpan nilai kualitas video bahkan saat mengubah kualitas video + Simpan nilai kualitas video setiap kali anda mengubah kualitas video + Aktifkan simpan kualitas video + Tapping seekbar diaktifkan + Aktifkan tapping seekbar + Bahkan jika brightness diatur ke 0 dengan swiping, brightness otomatis dinonaktifkan + Saat brightness mencapai 0 dengan swiping, brightness otomatis diaktifkan + Aktifkan brightness otomatis dengan swiping + Swipe brightness dinonaktifkan + Swipe brightness dinonaktifkan + Aktifkan gestur brightness + Feedback haptic tekan untuk swipe dinonaktifkan + Feedback haptic tekan untuk swipe diaktifkan + Aktifkan feedback haptic tekan untuk swipe + Swipe volume dinonaktifkan + Swipe volume diaktifkan + Aktifkan gestur volume + Tablet mini-player dinonaktifkan + Tablet mini-player diaktifkan + Aktifkan tablet mini-player + Trik dpi untuk menggunakan beberapa layout tablet + Aktifkan layout tablet + Search bar lebar dinonaktifkan + Search bar lebar diaktifkan + Aktifkan search bar lebar + Pengaturan eksperimental + Laporkan masalah atau tinggalkan saran di sini + Pusat masalah ReVanced Extended + Pengaturan ReVanced Extended + Pengaturan terkait Extended + Pengaturan Extended + Perbaiki masalah buffer pemutaran video dinonaktifkan + Perbaiki masalah buffer pemutaran video diaktifkan + Perbaiki masalah buffer pemutaran video + Captions diaktifkan saat memutar video dengan captions diterapkan + "Captions tidak diaktifkan saat memutar video dengan captions diterapkan" + Sembunyikan captions otomatis + Panel popup auto pemutar ditampilkan + Panel popup auto pemutar disembunyikan + Sembunyikan panel popup auto pemutar + Tombol autoplay ditampilkan + Tombol autoplay disembunyikan + Sembunyikan tombol autoplay + Menyembunyikan komponen wadah tombol + Sembunyikan komponen wadah tombol + Tombol clip ditampilkan + Tombol clip disembunyikan + Sembunyikan tombol clip + Tombol buat shorts ditampilkan + Tombol buat shorts disembunyikan + Sembunyikan tombol buat shorts + Tombol dislike ditampilkan + Tombol dislike disembunyikan + Sembunyikan tombol dislike + Tombol download ditampilkan + Tombol download disembunyikan + Sembunyikan tombol download + Tombol like ditampilkan + Tombol like disembunyikan + Sembunyikan tombol like + Tombol live chat ditampilkan + Tombol live chat disembunyikan + Sembunyikan tombol live chat + Tombol playlist ditampilkan + Tombol playlist disembunyikan + Sembunyikan tombol playlist + Tombol report ditampilkan + Tombol report disembunyikan + Sembunyikan tombol report + Tombol share ditampilkan + Tombol share disembunyikan + Sembunyikan tombol share + Tombol thanks ditampilkan + Tombol thanks disembunyikan + Sembunyikan tombol thanks + Tombol captions ditampilkan + Tombol captions disembunyikan + Sembunyikan tombol captions + Tombol cast ditampilkan + Tombol cast disembunyikan + Sembunyikan tombol cast + Watermark channel ditampilkan + Watermark channel disembunyikan + Sembunyikan watermark channel + Sembunyikan bagian komentar atau komponen + Sembunyikan komponen komentar + Bagian komentar ditampilkan + Bagian komentar disembunyikan + Sembunyikan bagian komentar + Tombol buat ditampilkan + Tombol buat disembunyikan + Sembunyikan tombol buat + Kotak crowdfunding ditampilkan + Kotak crowdfunding disembunyikan + Sembunyikan kotak crowdfunding + Alamat email ditampilkan + Alamat email disembunyikan + Sembunyikan alamat email + Kartu endscreen ditampilkan + Kartu endscreen disembunyikan + Sembunyikan kartu endscreen + Wadah tombol fullscreen ditampilkan + Wadah tombol fullscreen disembunyikan + Sembunyikan wadah tombol fullscreen + Kartu info ditampilkan + Kartu info disembunyikan + Sembunyikan kartu info + Menu mode ambient ditampilkan + Menu mode ambient disembunyikan + Sembunyikan menu mode ambient + Menu track audio ditampilkan + Menu track audio disembunyikan + Sembunyikan menu track audio + Menu captions ditampilkan + Menu captions disembunyikan + Sembunyikan menu captions + Menu & bantuan feedback ditampilkan + Menu & bantuan feedback disembunyikan + Sembunyikan menu & bantuan feedback + Menu kontrol listening ditampilkan + Menu kontrol listening disembunyikan + Sembunyikan menu kontrol listening + Menu dengarkan dengan YouTube Music ditampilkan + Menu dengarkan dengan YouTube Music disembunyikan + Sembunyikan menu dengarkan dengan YouTube Music + Menu video loop ditampilkan + Menu video loop disembunyikan + Sembunyikan menu video loop + Menu informasi lainnya ditampilkan + Menu informasi lainnya disembunyikan + Sembunyikan menu informasi lainnya + Menu report ditampilkan + Menu report disembunyikan + Sembunyikan menu report + Statistik untuk menu nerds ditampilkan + Statistik untuk menu nerds disembunyikan + Sembunyikan statistik untuk menu nerds + Menu tonton di VR ditampilkan + Menu tonton di VR disembunyikan + Sembunyikan menu tonton di VR + Playlist mix ditampilkan + Playlist mix disembunyikan + Sembunyikan playlist mix + Filter overlay pemutar ditampilkan + Filter overlay pemutar disembunyikan + Sembunyikan filter overlay pemutar + Komentar preview ditampilkan + Komentar preview disembunyikan + Sembunyikan komentar preview + Tombol shorts ditampilkan + Tombol shorts disembunyikan + Sembunyikan tombol shorts + Sembunyikan bagian shorts atau komponen pemutar shorts + Sembunyikan komponen shorts + Tombol komentar di pemutar shorts ditampilkan + Tombol komentar di pemutar shorts disembunyikan + Sembunyikan tombol komentar di pemutar shorts + Sembunyikan komponen pemutar shorts + Tombol remix di pemutar shorts ditampilkan + Tombol remix di pemutar shorts disembunyikan + Sembunyikan tombol remix di pemutar shorts + Tombol subscriptions di pemutar shorts ditampilkan + Tombol subscriptions di pemutar shorts disembunyikan + Sembunyikan tombol subscriptions di pemutar shorts + Tombol thanks di pemutar shorts ditampilkan + Tombol thanks di pemutar shorts disembunyikan + Sembunyikan tombol thanks di pemutar shorts + Rak shorts ditampilkan + Rak shorts disembunyikan + Sembunyikan rak shorts + Pemutar shorts dinonaktifkan saat memulai aplikasi + Pemutar shorts diaktifkan saat memulai aplikasi + Pemutar shorts saat memulai aplikasi + Rak stories ditampilkan + Rak stories disembunyikan + Sembunyikan rak stories + Suggested actions ditampilkan + Suggested actions disembunyikan + Sembunyikan suggested actions + Waktu dan seekbar ditampilkan + Waktu dan seekbar disembunyikan + Sembunyikan waktu dan seekbar + Pengaturan layout bawah pemutar + Pengaturan layout menu flyout + Pengaturan layout fullscreen + Pengaturan tata letak umum + Pengaturan layout pemutar + Pengaturan layout seekbar + Pengaturan terkait layout + Pengaturan layout + Pengaturan terkait lainnya + Pengaturan lain-lain + Lainnya + Tombol auto repeat disembunyikan + Tombol auto repeat ditampilkan + Tampilkan tombol auto repeat + Tombol copy link disembunyikan + Tombol copy link ditampilkan + Tampilkan tombol copy link + Tombol copy link dengan timestamp disembunyikan + Tombol copy link dengan timestamp ditampilkan + Tampilkan tombol copy link dengan timestamp + Tombol download disembunyikan + Tombol download ditampilkan + Tampilkan tombol download + Pengaturan terkait tombol overlay + Pengaturan tombol overlay + Tombol whitelist disembunyikan + Tombol whitelist ditampilkan + Tampilkan tombol whitelist + Header terkini: Header default + Header terkini: Header premium + Header premium + Informasi tentang patch yang diterapkan + Informasi patch + Menyembunyikan komponen panel flyout pengaturan pemutar + Komponen panel flyout pemutar + "Karena ini masih merupakan fitur percobaan, mungkin ada masalah lain yang tidak diketahui. +Apakah anda yakin ingin melanjutkan?" + "Trik versi klien YouTube ke v17.28.35 untuk memuat layout lama + +Di pengaturan aplikasi, versi YouTube mungkin ditandai sebagai v17.28.35" + "Trik dpi untuk mengubah beberapa layout menjadi layout ponsel. + +Jika anda mengaktifkan pengaturan ini, fitur berikut akan tersedia: +- Postingan komunitas +- Sembunyikan playlist mix" + "Perbaiki masalah buffer pemutaran video di beberapa wilayah/negara. + +Jika anda mengaktifkan pengaturan ini, masalah berikut mungkin terjadi: +- Saat memutar video di playlist, masalah mungkin tidak dapat diperbaiki" + "Trik dpi untuk mengubah beberapa layout menjadi layout tablet. + +Jika anda mengaktifkan pengaturan ini, fitur berikut tidak tersedia: +- Mode ambient +- Postingan komunitas" + Data dislike disediakan oleh API True RYD Worker. Tekan disini untuk mempelajari lebih lanjut. + true-ryd.cane.workers.dev + API mirror dinonaktifkan + API mirror diaktifkan + Aktifkan API mirror + "True RYD Worker API menghilangkan pengajuan voting dan proses pendaftaran. +Dengan demikian, ini kurang tepat daripada API RYD default. + +Aktifkan opsi ini hanya untuk mereka yang mengalami masalah saat menggunakan API RYD default. + +Apakah anda ingin melanjutkan?" + True RYD Worker + Data dislike disediakan oleh API Return YouTube Dislike. Tekan di sini untuk mempelajari lebih lanjut. + ReturnYouTubeDislike.com + Dislike ditampilkan sebagai angka + Dislike ditampilkan sebagai persentase + Dislike sebagai persentase + Dislike tidak ditampilkan + Dislike ditampilkan + Return YouTube Dislike + Dislikes tidak tersedia (batas API client tercapai) + ReturnYouTubeDislike gagal mengonfirmasi user baru + ReturnYouTubeDislike gagal mengonfirmasi vote + Dislikes untuk sementara tidak tersedia (waktu API habis) + ReturnYouTubeDislike gagal mendaftar sebagai user baru + ReturnYouTubeDislike gagal mengonfirmasi vote + Pengaturan terkait Return YouTube Dislike + Return YouTube Dislike + Pengaturan ReVanced + Pengaturan terkait kontrol swipe + Pengaturan kontrol swipe + Jumlah ambang batas untuk swipe terjadi + Ambang besar swipe + Visibilitas background overlay swipe + Visibilitas background swipe + Ukuran teks untuk overlay swipe + Ukuran teks overlay swipe + Jumlah milidetik overlay terlihat + Batas waktu overlay swipe + alat yang digunakan + Iklan video ditampilkan + Iklan video disembunyikan + Sembunyikan iklan video + Gagal menyetel kualitas + Tidak ada koneksi internet + Mengubah kualitas data seluler default menjadi: + Gagal mengubah kualitas data seluler default + Mengubah kualitas Wi-Fi default menjadi: + Gagal mengubah kualitas WI-FI default + Pengaturan terkait video + Pengaturan video + Gagal menambahkan channel %s ke %s whitelist + Channel %s telah ditambahkan ke %s whitelist + Iklan video + Iklan + Nama channel + Tidak ada channel yang masuk whitelist + Tidak ditambahkan ke whitelist + Ditambahkan ke whitelist + Whitelist channel + Gagal mengambil detail channel, menerima kode %d + Reboot untuk menerapkan pengaturan whitelist channel + Gagal menghapus channel %s dari %s whitelist + Channel %s telah dihapus dari %s whitelist + Periksa atau hapus channel yang ditambahkan ke whitelist + Pengaturan whitelist + Kecepatan video + Kecepatan + SponsorBlock + SB + Server Sponsorblock tidak merespons! + Sudah dibaca + "Disarankan untuk membaca pedoman SponsorBlock sebelum mengirimkan segmen apa pun" + Tunjukkan padaku + Ada pedoman + Pedoman berisi tips dan aturan tentang mengirimkan segmen + Lihat pedoman + Pengaturan SponsorBlock + Pengaturan terkait SponsorBlock + Berhasil beralih. memuat ulang video + Mengalihkan server mirror API ke server API utama.. + Endcards/kredit + Kredit atau saat kartu akhir YouTube muncul. Bukan untuk kesimpulan yang diucapkan + Filler tangent/lelucon + Adegan tangensial ditambahkan hanya untuk filler atau humor yang tidak diperlukan untuk memahami isi utama video. Ini tidak boleh menyertakan konteks atau detail latar belakang + Intermission/animasi intro + Interval tanpa konten sebenarnya. Bisa berupa jeda, static frame, animasi berulang + Musik: bagian non-musik + Hanya untuk digunakan dalam video musik. Lewati bagian video yang tidak ada dalam official mixes + Preview/rekap + "Rekap episode sebelumnya, atau preview tentang apa yang akan muncul nanti di video saat ini atau video mendatang dalam serial yang sama. Klip tidak boleh memberikan informasi tambahan." + Promosi tidak dibayar/diri sendiri + Ketika ada promosi yang tidak dibayar atau promosi diri sendiri. Ini termasuk bagian khusus tentang merchandise, donasi, atau informasi tentang dengan siapa mereka bekerja sama + Sponsor + Promosi berbayar, referensi berbayar, dan iklan langsung + Pengingat interaksi (subscribe) + Ketika ada pengingat singkat untuk like, subscribe, follow, atau berinteraksi dengan mereka di platform gratis atau berbayar apa pun + Gagal mengekspor pengaturan + Pengaturan impor/ekspor + Ini adalah seluruh konfigurasi anda yang berlaku di ekstensi desktop di JSON. Ini termasuk userID pribadi anda, jadi pastikan untuk membagikannya dengan bijak. + Gagal mengimpor pengaturan + Pengaturan berhasil diimpor + Lewati secara otomatis + Lewati secara otomatis sekali + "Jangan lakukan apapun" + Tampilkan tombol lewati + Segmen dilewati + Outro dilewati + Filler dilewati + Intro dilewati + Melewatkan bagian non-musik + Preview dilewati + Melewatkan segmen sponsor + Melewatkan promosi diri + Sponsor dilewati + Pengingat yang mengganggu dilewati + Melewati segmen yang belum dikirim + Statistik + Loading.. + "Anda telah menyelamatkan orang-orang dari <b>%s</b> segmen." + "Itu <b>%s</b> hidup mereka. Tekan untuk melihat leaderboard" + SponsorBlock dinonaktifkan + "Anda telah melewatkan <b>%s</b> segmen." + "Itu <b>%s</b>." + Submissions: <b>%s</b> + Username anda: <b>%s</b> + Tekan untuk mengubah username anda + Tidak dapat mengubah username: Status: %d %s + Username berhasil diubah + "Tidak dapat mengirimkan segmen. +Sudah ada" + "Tidak dapat mengirimkan segmen. + +%s" + "Tidak dapat mengirimkan segmen. +Rate Limited (Terlalu banyak dari user atau IP yang sama)" + Tidak dapat mengirimkan segmen: %s + Tidak dapat memilih segmen: Status: %d %s + Mengirimkan segmen… + Segmen berhasil dikirim + Tekan untuk melewati + Ubah kategori + Downvote + "Tidak dapat memilih segmen. + +%s" + "Tidak dapat memilih segmen. +Rate Limited (Terlalu banyak dari user atau IP yang sama)" + Tidak dapat memilih segmen: Status: %d %s + Tidak ada segmen untuk dipilih + Voting untuk segmen… + Vote berhasil + Upvote + diff --git a/src/main/resources/youtube/translations/ja-rJP/strings.xml b/src/main/resources/youtube/translations/ja-rJP/strings.xml new file mode 100644 index 000000000..0a78d0fd2 --- /dev/null +++ b/src/main/resources/youtube/translations/ja-rJP/strings.xml @@ -0,0 +1,615 @@ + + + 概要 + このアプリは Sponsor Block の API を使用しています + 詳細についてはこちらをタップしてください。他のプラットフォームへのダウンロードは sponsor.ajay.app をご覧ください。 + JakubWeg による統合 + 動画プレーヤーのアクセシビリティコントロールをオンにしますか? + アクセシビリティサービスがオンになっているため、コントロールは変更されます。 + API の URL を変更しました + 指定された API の URL が無効です + API の URL をリセットしました + API ミラー URL が変更されました + 指定されたAPI ミラー URLが無効です + API ミラー URL がリセットされました + 色の変更をお探しですか? + "上記のカテゴリをクリックすることで、カテゴリの色を変更できます。" + 色を変更しました + 無効な16進数コードです + 色をリセット + セグメントの設定 + SponsorBlock を有効にする + SponsorBlock は、YouTube動画の迷惑/無駄な部分をスキップするためのクラウドソースシステムです + SponsorBlock を有効にする + SponsorBlock APIサーバーがダウンした場合、ミラーAPIサーバーをデフォルトAPIサーバーに切り替えます。 + 新しいセグメントの追加を有効にする + 実験的なセグメントの追加を有効にするにはこれをオンにします(ボタンの表示に問題があります) + 投票機能を有効にする + 投票機能を有効にするには、これをオンにしてください。 + 一般設定 + 新しいセグメントのステップを調整する + これは、新しいセグメントを追加する際に時間調整ボタンを使用したときに移動できるミリ秒数です。 + API の URL を変更 + "SponsorBlock がサーバーの呼び出しに使用するアドレスです。 <b>意味が分からない場合は変更しないでください。</b>" + API ミラー URL を変更 + "SponsorBlock サーバーがダウンしたときに切り替えるミラー サーバー アドレスです。 <b>何をしているか分からない場合は変更しないでください。</b>" + 最小のセグメントの長さ + 設定値 (単位: 秒) より短いセグメントはスキップされず、プレーヤーにも表示されません + スキップ回数の追跡 + SponsorBlock のリーダーボードシステムはユーザーがどれくらい時間を節約したかを知ることができます。 拡張機能はセグメントをスキップするたびにサーバーにメッセージを送信します + セグメントを自動的にスキップするときにトーストを表示する + タップしてサンプルトーストを見る + セグメントを除いた時間を表示 + この時間は、現在の時間の横にある( )内に表示されます。これは、動画の合計再生時間からセグメントを差し引いたものです。 + あなたのプライベート ユーザー ID + これは非公開にする必要があります。パスワードのようなもので誰とも共有するべきではありません。誰かがこれを持っている場合、あなたになりすますことができます。 + MicroGをインストールしてください + MicroGが見つかりません + 通知設定 + "1. 通知のために、Google デバイスの登録とCloud Messaging を有効にする必要があります。 +2. ReVanced は Cloud Messaging に登録済みとして表示される必要があります。 +3. Cloud Messaging の現在の状態は接続済みである必要があります。" + MicroGの設定 + + セグメントのカテゴリを選択してください + "このセグメントは %02d:%02d から %02d:%02d (%d 分 %02d 秒間)です +送信してよろしいですか?" + 時間は正しいですか? + "設定でこのカテゴリを無効にしました。送信できるように有効にしてください" + セグメントの開始または終了のタイミングを編集しますか? + 無効な時間の値です + 完了 + セグメントのタイミングを手動で編集 + 終了 + 最初にタイムバーに 2 つの場所をマークしてください + 開始 + %02d:%02d:%04d を新しいセグメントの開始または終了として設定しますか? + 現在 + セグメントの終了時刻 + セグメント設定の終了 + セグメントの開始時刻 + セグメント設定の開始 + 新しい SponsorBlock セグメント + リセット + 広告関連の設定 + 広告の設定 + アルバムカードは検索結果に表示されます + アルバム カードは検索結果に表示されません + アルバムカード + ニュース速報のパネルは表示されます + ニュース速報のパネルは非表示です + ニュース速報のパネル + ホームの広告は表示されます + ホームの広告は非表示です + ホームの広告 + チャンネルガイドラインは表示されます + チャンネルガイドラインは非表示です + チャンネルガイドライン + チャプターは表示されます + チャプターは非表示です + シークバーに表示されるチャプター + コミュニティガイドラインは表示されます + コミュニティガイドラインは非表示です + コミュニティガイドライン + コミュニティの投稿は表示されます + コミュニティの投稿は非表示です + コミュニティの投稿 + コンパクトなバナーは表示されます + コンパクトなバナーは非表示です + コンパクトなバナー + コンマで区切られた名前でコンポーネントをフィルタリングします + カスタムフィルター + 電話相談ボックスは表示されます + 電話相談ボックスは非表示です + 電話相談ボックス + 一般的な広告は表示されます + 一般的な広告は非表示です + 一般的な広告 + 画像欄は表示されます + 画像欄は非表示です + 画像欄 + 情報パネルは表示されます + 情報パネルは非表示です + 情報パネル + アンケートは表示されます + アンケートは非表示です + アンケート + 最新の投稿は表示されます + 最新の投稿は非表示です + 最新の投稿 + 医療パネルは表示されます + 医療パネルは非表示です + 医療パネル + 商品バナーは表示されます + 商品バナーは非表示です + 商品バナー + 映画欄は表示されます + 映画欄は非表示です + 映画欄 + 公式チャンネル/動画(公式カード)は検索結果の一番上に表示されます + 公式チャンネル/動画(公式カード)は検索結果の一番上に表示されません + 公式チャンネル/動画(公式カード)を検索結果の一番上に表示 + 有料コンテンツは表示されます + 有料コンテンツは非表示です + 有料コンテンツ + 自己スポンサーカードは表示されます + 自己スポンサーカードは非表示です + 自己スポンサーカード + 灰色の区切りは表示されます + 灰色の区切りは非表示です + 灰色の区切り + 一般的な提案は表示されます + 一般的な提案は非表示です + 提案 + コメント欄のリアクション(一部の動画のみ表示)は表示されます + コメント欄のリアクション(一部の動画のみ表示)はは非表示です + コメント欄のリアクション(一部の動画のみ表示) + ユーザー フィルタは無効です + ユーザー フィルタは有効です + ユーザーフィルターを有効にする + 商品バナーは表示されます + 商品バナーは非表示です + 商品バナー + ウェブ検索パネルは表示されます + ウェブ検索パネルは非表示です + ウェブ検索パネル + プレーヤーがバッファリングしようとするメディアの最大時間 + バッファリングの最大値 + シーク移動などのユーザーアクションの後に再生を開始または再開するためのバッファリングを行う時間 + 再生開始バッファサイズ + 再バッファ後に再生を再開するためにバッファリングする必要があるメディアの時間 + 再バッファリングサイズ + 動画バッファリングサイズ関連の設定 + バッファリングの設定 + モバイルデータ通信でのデフォルト画質を選択 + モバイルデータ通信でのデフォルト画質 + Wi-Fi でのデフォルト画質の選択 + Wi-Fi でのデフォルト画質 + デフォルトの動画再生速度を選択 + デフォルトの再生速度 + はインストールされていません。インストールしてください。 + "NewPipeやPowerTubeなどのダウンローダーアプリのパッケージ名" + ダウンローダーのパッケージ名 + デフォルトの動画ダウンローダー関連の設定 + 動画ダウンローダーの設定 + 終了画面オーバーレイは表示されます + 終了画面オーバーレイは非表示です + 終了画面オーバーレイ + 動画プレーヤーの映写スライドは表示されます + 動画プレーヤーの映写スライドは非表示です + 動画プレーヤーの映写スライド + 触覚(振動)フィードバックのスクラブは有効です + 触覚(振動)フィードバックのスクラブは無効です + 触覚(振動)フィードバックのスクラブ + 触覚(振動)フィードバックは有効です + 触覚(振動)フィードバックは無効です + 触覚(振動)フィードバック + チャプターの触覚(振動)フィードバックは有効です + チャプターの触覚(振動)フィードバックは無効です + チャプターの触覚(振動)フィードバック + 長押し時の触覚(振動)フィードバックを無効にします + 触覚(振動)フィードバックを無効にする + 動画をズームする時の触覚(振動)フィードバックは有効です + 動画をズームする時の触覚(振動)フィードバックは無効です + 動画をズームする時の触覚(振動)フィードバック + タイムスタンプをコピーしました + 常に自動リピートはオフです + 常に自動リピートは有効です + 常に自動リピート + プレーヤーコントロールが表示されているときにスワイプジェスチャーを無効にする + 表示または非表示に関係なく常にスワイプジェスチャーを有効にする + 常にスワイプジェスチャーを有効にする + カスタム再生速度は無効です + カスタム再生速度は有効です + カスタム動画再生速度 + 外部ブラウザは無効です + 外部ブラウザは有効です + 外部ブラウザ + 自動明るさ調整は無効です + 自動明るさ調整は有効です + 自動明るさ調整 + 最小化再生は無効です + 最小化再生は有効です + 最小化再生 + YouTubeのレイアウトはGoogleアカウントのステータスに従います + 強制的に古いレイアウトを有効にするために、YouTubeのバージョンを偽装します + 古いレイアウトを有効にする + 新しい形式の画質設定を使用する + 古い形式の画質設定を使用する + 古い形式の画質設定画面を有効にする + URL リダイレクト (youtube.com/redirect) は、動画の概要欄のリンクを開くときに使用されます + 概要欄からリンクを開いたとき、URLリダイレクト(youtube.com/redirect)を回避して、直リンクにします + 直リンクを有効にする + スワイプコントロールは無効です + スワイプコントロールは有効です + スワイプコントロール + 一部のスマホ用のレイアウトを使用出来るようにに dpi を偽装します + スマートフォン用のレイアウト + シークバー(動画進捗バー)のタップは有効です + 動画の画質を変更しても画質の値は保存されません + 動画の画質を変更するたびに、画質の値が保存されます + 動画の画質を保存 + シークバー(動画進捗バー)のタップは有効です + シークバー(動画進捗バー)のタップ + スワイプで明るさが0に設定されていても、自動明るさ調整は働きません + スワイプして明るさが0になると自動明るさ調整が働きます + スワイプして明るさを自動調整 + 明るさのスワイプコントロールは無効です + 明るさのスワイプコントロールは有効です + 明るさのスワイプコントロール + スワイプコントロールの触覚(振動)フィードバックは無効です + スワイプコントロールの触覚(振動)フィードバックは有効です + スワイプコントロールの触覚(振動)フィードバック + 音量のスワイプコントロールは無効です + 音量のスワイプコントロールは有効です + 音量のスワイプコントロール + タブレットのミニプレーヤーは無効です + タブレットのミニプレーヤーは有効です + タブレットのミニプレーヤー + 一部のタブレット用のレイアウトを使用出来るようにに dpi を偽装します + タブレット用のレイアウト + 幅広い検索バーは無効です + 幅広い検索バーは有効です + 幅広い検索バー + 実験的な機能 + 問題を報告するか、提案をここに残してください + ReVanced Extended 問題 センター + ReVanced Extended の設定 + Extended 関連の設定 + Extended の設定 + 動画再生バッファリングの問題を修正 は無効です + 動画再生バッファリングの問題を修正 は有効です + 動画再生バッファリングの問題を修正する + 字幕付きの動画が再生されると強制的に字幕が有効になります + "字幕付きの動画が再生されても強制的に字幕が有効になりません" + 自動で字幕を表示 + プレーヤーのポップアップ パネルは自動的に表示されます + プレーヤーのポップアップ パネルは自動的に表示されません + プレーヤーのポップアップ パネル + 自動再生ボタンは表示されます + 自動再生ボタンは非表示です + 自動再生ボタン + ボタンコンテナのコンポーネント(高評価ボタン、共有ボタンなど)を非表示にします + ボタンコンテナのコンポーネントを非表示にする + クリップボタンは表示されます + クリップボタンは非表示です + クリップボタン + ショートの作成ボタンは表示されます + ショートの作成ボタンは非表示です + ショートの作成ボタン + 低評価ボタンは表示されます + 低評価ボタンは非表示です + 低評価ボタン + ダウンロードボタンは表示されます + ダウンロードボタンは非表示です + ダウンロードボタン + 高評価ボタンは表示されます + 高評価ボタンは非表示です + 高評価ボタン + ライブチャットボタンは表示されます + ライブチャットボタンは非表示です + ライブチャットボタン + プレイリストボタンは表示されます + プレイリストボタンは非表示です + プレイリストボタン + 報告ボタンは表示されます + 報告ボタンは非表示です + 報告ボタン + 共有ボタンは表示されます + 共有ボタンは非表示です + 共有ボタン + Thanksボタンは表示されます + Thanksボタンは非表示です + Thanksボタン + 字幕ボタンは表示されます + 字幕ボタンは非表示です + 字幕ボタン + キャストボタンは表示されます + キャストボタンは非表示です + キャストボタン + チャンネルの透かし(ウォーターマーク)は表示されます + チャンネルの透かし(ウォーターマーク)は非表示です + チャンネルの透かし(ウォーターマーク) + コメント欄やコンポーネント(高評価ボタン、共有ボタンなど)を非表示にする + コメントのコンポーネント + コメント欄は表示されます + コメント欄は非表示です + コメント欄 + 作成ボタンは表示されます + 作成ボタンは非表示です + 作成ボタン + クラウドファンディング欄は表示されます + クラウドファンディング欄は非表示です + クラウドファンディング欄 + メールアドレスは表示されます + メールアドレスは非表示です + メールアドレス + 終了画面のカード(別動画の表示)は表示されます + 終了画面のカード(別動画の表示)は非表示です + 終了画面のカード + 全画面表示のボタンは表示されます + 全画面表示のボタンは非表示です + 全画面表示のボタン + 情報カードは表示されます + 情報カードは非表示です + 情報カード + アンビエントモードのメニューは表示されます + アンビエントモードのメニューは非表示です + アンビエントモードのメニュー(動画プレーヤー上の設定内にあります) + オーディオトラックメニューは表示されます + オーディオトラックメニューは非表示です + オーディオトラックメニュー + 字幕メニューは表示されます + 字幕メニューは非表示です + 字幕メニュー + ヘルプとフィードバック メニューは表示されます + ヘルプとフィードバック メニューは非表示です + ヘルプとフィードバック メニュー + リスニングコントロールメニューは表示されます + リスニングコントロールメニューは非表示です + リスニングコントロールメニュー + ”YouTube Music で聴く” メニューは表示されます + ”YouTube Music で聴く” メニューは非表示です + ”YouTube Music で聴く” メニュー + 動画のループ再生 メニューは表示されます + 動画のループ再生 メニューは非表示です + 動画のループ再生 メニュー + 詳細メニューは表示されます + 詳細メニューは非表示です + 詳細メニュー + 報告メニューは表示されます + 報告メニューは非表示です + 報告メニュー + 動画プレーヤー上の設定メニューは表示されます + 動画プレーヤー上の設定メニューは非表示です + 動画プレーヤー上の設定メニュー + “VRで見る” メニューは表示されています + “VRで見る” メニューは非表示です + “VRで見る” メニュー + ミックスリストは表示されます + ミックスリストは非表示です + ミックスリストを非表示 + プレーヤーオーバーレイフィルター(画面を一回タップすると薄暗くなるやつ)は表示されます + プレーヤーオーバーレイフィルター(画面を一回タップすると薄暗くなるやつ)は非表示です + プレーヤーオーバーレイフィルター(画面を一回タップすると薄暗くなるやつ) + コメントのプレビューは表示されます + コメントのプレビューは非表示です + コメントのプレビュー + ショートボタンは表示されます + ショートボタンは非表示です + ショートボタン + ショートセクションまたはショートプレーヤーを非表示にします + ショートのコンポーネント(高評価ボタン、共有ボタンなど) + ショートのコメントのボタンは表示されます + ショートのコメントのボタンは非表示です + ショートのコメントのボタン + ショートのプレイヤーのコンポーネント(高評価ボタン、共有ボタンなど) + ショートプレーヤーのリミックスボタンは表示されます + ショートプレーヤーのリミックスボタンは非表示です + ショートプレーヤーのリミックスボタン + ショートプレーヤーのサブスクボタンは表示されます + ショートプレーヤーのサブスク ボタンは非表示です + ショートプレーヤーのサブスク ボタン + ショートのプレーヤーの感謝ボタンは表示されます + ショートのプレイヤーの感謝ボタンは非表示です + ショートのプレイヤーの感謝ボタン + ショート欄は表示されます + ショート欄は非表示です + ショート欄 + アプリの起動時にショートプレーヤーは無効になっています + アプリの起動時にショートプレーヤーは有効になっています + アプリ起動時のショートプレーヤー + ストーリー欄は表示されます + ストーリー欄は非表示です + ストーリー欄 + 提案されたアクションは表示されます + 提案されたアクションは非表示です + 提案されたアクション + 時間とシークバーは表示されます + 時間とシークバーは非表示です + 時間とシークバー + 下のプレイヤーのレイアウト設定 + 動画プレーヤー上の設定メニューのレイアウト設定 + 全画面表示のレイアウトの設定 + 一般的なレイアウトの設定 + 動画プレーヤーのレイアウト設定 + シークバーのレイアウト設定 + レイアウト関連の設定 + レイアウトの設定 + その他の関連設定 + その他の設定 + その他 + 自動リピートボタンは非表示です + 自動リピートボタンは表示されます + 自動リピートボタン + リンクをコピーするボタンはプレーヤー上で非表示になっています + リンクをコピーするボタンはプレーヤー上で表示されます + “リンクをコピー” ボタン + “タイムスタンプ付きのリンクをコピー”ボタンは非表示です + “タイムスタンプ付きのリンクをコピー”ボタンは表示されます + “タイムスタンプ付きのリンクをコピー” ボタン + ダウンロードボタンは非表示です + ダウンロードボタンは表示されます + 動画のダウンロードボタン + オーバーレイボタンに関する設定 + オーバーレイボタンの設定 + ホワイトリストのボタンは非表示です + ホワイトリストのボタンは表示されます + ホワイトリストのボタン + 現在のヘッダー: デフォルトのヘッダー + 現在のヘッダー: YouTubeプレミアムヘッダー + YouTubeプレミアムヘッダー + 適用されたパッチに関する情報 + パッチの情報 + 動画プレーヤー上の設定ボタンのコンポーネントを非表示にします + 動画プレーヤー上の設定ボタンのコンポーネント + "これはまだ実験的な機能なので、他にも未知のバグがあるかもしれません。 +続行してもよろしいですか?" + "古いレイアウトを有効にするために、YouTubeのバージョンをv17.28.35に偽装します。 + +アプリの設定では、YouTubeのバージョンはv17.28.35 と表示されます。" + "一部のレイアウトをスマートフォン用のレイアウトに変更するために dpi を偽装します。 + +この設定を有効にすると、次の機能は利用できません: +- アンビエントモード +- コミュニティの投稿" + "一部の国/地域で動画再生バッファリングの問題を修正しました。 + +この設定を有効にすると、次の問題が発生する可能性があります: +- プレイリスト内の動画を再生する場合、問題が修正されない可能性があります" + "一部のレイアウトをタブレット用のレイアウトに変更するために dpi を偽装します。 + +この設定を有効にすると、次の機能は利用できません: +- アンビエントモード +- コミュニティの投稿" + 低評価のデータは、True RYD Worker APIによって提供されます。詳細はここをタップしてください。 + true-ryd.cane.workers.dev + ミラー API は無効です + ミラー API は有効です + ミラー API + "True RYD Worker API は、YouTube API エンドポイントで公開されている低評価数を使用します。 +デフォルトの RYD API の使用中に問題が発生した場合にのみ、このオプションを有効にしてください。 +続行しますか?" + True RYD Worker + 低評価のデータは、Return YouTube Dislike API によって提供されます。詳細はこちらをタップしてください。 + ReturnYouTubeDislike.com + 低評価数を数字で表示 + 低評価数をパーセントで表示します + 低評価数をパーセントで表示 + 低評価数は非表示です + 低評価数は表示されます + 低評価数を表示する(Return YouTube Dislike) + 低評価数は利用できません (クライアント API の制限に達しました) + ReturnYouTubeDislike は新しいユーザーを確認できませんでした + ReturnYouTubeDislike は投票を確認できませんでした + 低評価数は一時的に利用できません (API がタイムアウトしました) + ReturnYouTubeDislike は新しいユーザーを確認できませんでした + ReturnYouTubeDislike は投票を送信できませんでした + 低評価数の表示(Return YouTube Dislike) の設定 + 低評価数の表示(Return YouTube Dislike) + Revancedの設定 + スワイプコントロール関連の設定 + スワイプコントロールの設定 + スワイプのしきい値を設定します + スワイプのしきい値 + オーバーレイの背景の透明度 (0–255) + オーバーレイの背景の透明度 + オーバーレイ上のテキストサイズを変更します + オーバーレイのテキストサイズ + 変更後にオーバーレイが表示される時間 (単位: ミリ秒) + オーバーレイのタイムアウト + 使用されたツール + 動画の広告は表示されます + 動画の広告は非表示です + 動画の広告 + 画質を設定できませんでした + インターネットに接続できません + モバイルデータ通信で優先する画質: + モバイルデータ通信で優先する画質を変更できませんでした + Wi-Fi で優先する画質: + Wi-Fi で優先する画質を変更できませんでした + 動画関連の設定 + 動画の設定 + チャンネル %s を %s ホワイトリストに追加できませんでした + チャンネル %s は %s ホワイトリストに追加されました + 動画の広告 + 広告 + チャンネル名 + ホワイトリストに登録されたチャンネルはありません + ホワイトリストに追加されていません + ホワイトリストに追加 + チャンネルのホワイトリスト + チャンネル詳細の取得に失敗しました。受信したコード : %d + チャンネルホワイトリスト設定を適用するには再起動してください + チャンネル %s を %s ホワイトリストから削除できませんでした + チャンネル %s は %s ホワイトリストから削除されました + ホワイトリストに追加されたチャンネルのリストを確認または削除する + ホワイトリストの設定 + 動画の再生速度 + 再生速度 + SponsorBlock + Sponsor Block + Sponsorblock サーバーは応答していません! + 既に読んでいます + "セグメントを提出する前に、スポンサーブロックガイドラインを読むことをお勧めします" + 見る + ガイドラインがあります + ガイドラインには、セグメントの送信に関するヒントとルールが含まれています + ガイドラインを表示 + SponsorBlockの設定 + SponsorBlock 関連の設定 + 切り替えに成功しました。動画を再読み込みしてください + ミラー API サーバーをメイン API サーバーに切り替えます。 + エンドカード/クレジット + 提供表示やYouTubeの終了画面が表示されている場面。動画の内容を結論している場面には使用しないで下さい。 + 繋ぎの話(無駄話など)/冗談 + 脱線したシーンには、動画の主な内容を理解するのに必要がない穴埋めやユーモアのみを追加してください。これには、文脈や背景の詳細を提供するセグメントを含めないでください。 + 休憩/イントロアニメーション + 内容のない間。一時停止、静的フレーム、繰り返しのアニメーションなど + 音楽ではない区間 + ミュージックビデオでのみ使用できます。公式ミックスに含まれていない動画の部分をスキップします + 予告/あらすじ + "前回の動画のあらすじや動画後半の内容の予告。ただ話しているものではなく、映像が編集されているものを指します。" + 無報酬/セルフプロモーション + 無報酬またはセルフプロモーションを除いてスポンサーと同様です。商品、寄付、または誰とコラボしたかに関するセクションが含まれます + スポンサー + 有料プロモーション、有料紹介、ダイレクト広告 + インタラクション リマインダー (チャンネル登録) + 動画の途中に高評価、チャンネル登録、フォローの短いリマインダーがある場合 + 設定のエクスポートに失敗しました + 設定のインポート/エクスポート + これはデスクトップ拡張機能で適用される設定全体のJSONです。ユーザーIDが含まれているため、共有には気をつけてください。 + 設定のインポートに失敗しました + 設定が正常にインポートされました + 自動的にスキップ + 一度だけ自動的にスキップする + "何もしない" + スキップボタンを表示 + セグメントをスキップ + アウトロをスキップしました + つなぎシーンをスキップしました + イントロをスキップしました + 音楽以外のセクションをスキップしました + プレビューをスキップしました + スポンサーセグメントをスキップしました + セルフプロモーションをスキップしました + スポンサーをスキップしました + 迷惑なリマインダーをスキップしました + 未送信のセグメントをスキップしました + 統計情報 + 読み込み中... + "今まで <b>%s</b> 個のセグメントから人々を守りました。" + "あなたは合計で人々の人生を <b>%s</b> 回無駄にせずに済みました。クリックしてリーダーボードを確認します。" + SponsorBlockは無効です + "今まで <b>%s</b> 個のセグメントをスキップしました。" + "合計 <b>%s</b> です。" + 投稿したセグメントの数: <b>%s</b> + あなたのユーザー名: <b>%s</b> + タップしてユーザー名を変更する + ユーザー名を変更できませんでした。ステータス: %d %s + ユーザー名は正常に変更されました + "セグメントを送信できません +既に存在します" + "セグメントを送信できません。 + +%s" + "セグメントを送信できません。 +レート制限 (同じユーザーやIPからの送信が多すぎます)" + セグメントを送信できません: %s + セグメントを送信できません。ステータス: %d %s + セグメントを送信しています… + セグメントが正常に送信されました + タップしてスキップ + カテゴリーを変更する + 低評価 + "セグメントに投票できません。 + +%s" + "セグメントに投票できません。 +レート制限 (同じユーザーやIPからの送信が多すぎます)" + セグメントへの投票に失敗しました。ステータス: %d %s + 投票できるセグメントがありません + セグメントへ投票しています… + 投票しました + 高評価 + diff --git a/src/main/resources/youtube/translations/ko-rKR/strings.xml b/src/main/resources/youtube/translations/ko-rKR/strings.xml new file mode 100644 index 000000000..f28868463 --- /dev/null +++ b/src/main/resources/youtube/translations/ko-rKR/strings.xml @@ -0,0 +1,207 @@ + + + 정보 + 이 앱은 SponsorBlock의 API를 사용합니다. + 다른 플랫폼에서 다운로드하는 방법은 sponsor.ajay.app에서 확인할 수 있습니다. 자세한 정보를 보려면 누르세요. + JakubWeg님이 개발하였습니다. + 플레이어에서 접근성 컨트롤을 표시하겠습니까? + 접근성 서비스가 켜져있기 때문에 플레이어 컨트롤이 변경되었습니다. + API URL이 변경되었습니다. + 입력한 API URL이 잘못되었습니다. + API URL 초기화 + API MIRROR URL이 변경되었습니다. + 입력한 API MIRROR URL이 잘못되었습니다. + API MIRROR URL 초기화 + 색상 변경 기능을 찾고 있으신가요? + "이제 위의 카테고리를 클릭하여 카테고리의 색상을 변경할 수 있습니다." + 색상이 변경되었습니다. + 잘못된 헥스코드입니다. + 색상 초기화 + 각 구간에 설정할 동작 + SponsorBlock 활성화 + SponsorBlock은 YouTube 동영상 내 성가신 구간을 건너뛰게 해주는 크라우드소싱 시스템입니다. + SponsorBlock Mirror 활성화 + SponsorBlock API 서버가 중단되면 Mirror API 서버가 기본 API 서버로 전환됩니다. + 새로운 구간 추가 버튼 활성화 + 플레이어에 새로운 구간 추가 버튼을 추가합니다. (버튼이 잘 안 보일 수도 있습니다.) + 투표 버튼 활성화 + 플레이어에 투표 버튼을 추가합니다. + 일반 설정 + 구간 추가 시 슬라이더 단위 조정 + 새로운 구간 추가 시에 시간 빨리감기 또는 되감기 버튼을 눌렀을 때 이동할 수 있는 시간으로, 단위는 밀리초입니다. + API URL 변경 + "SponsorBlock이 요청을 보낼 서버 주소입니다. <b>이것이 무슨 역할을 하는지 알고 있는 경우에만 이 주소를 변경하십시오.</b>" + API Mirror URL 변경 + "SponsorBlock 서버가 중단될 때 전환할 Mirror 서버 주소입니다. <b>이것이 무슨 역할을 하는지 알고 있는 경우에만 이 주소를 변경하십시오.</b>" + 최소 구간 길이 + 설정한 값(초)보다 작은 구간은 건너뛰지 않으며, 재생 바에 표시되지 않습니다. + 건너뛴 횟수 추적 + 이 기능을 사용하면 사용자가 구간 건너뛰기를 통해 절약한 시간을 SponsorBlock의 리더보드 시스템에 알려줍니다. 구간을 건너뛸 때마다 서버에 자동으로 관련 정보를 전송합니다. + 자동으로 구간을 건너뛸 때 팝업 메시지 표시 + 팝업 메시지 예시를 보려면 클릭하세요 + 구간을 제외한 시간 표시 + 이 시간은 현재 시간 옆에 있는 괄호 안에 표시되며, 건너뛸 구간을 제외한 전체 동영상 길이를 보여줍니다. + 비공개 사용자 ID + 이 정보를 다른 분께 공개하지 마세요. 이건 비밀번호와 같으며 누구와도 공유해서는 안 되는 정보입니다. 다른 분이 이 정보를 습득한다면, 나를 사칭할 수도 있습니다. + MicroG를 설치해 주세요 + MicroG가 설치되지 않았습니다. + 알림 설정 + "1. 알림을 받으려면 Google 기기 등록 및 클라우드 메시징을 활성화해야 합니다. +2. ReVanced Extended가 클라우드 메시징에 등록된 앱으로 표시되어야 합니다. +3. 클라우드 메시징의 현재 상태가 연결 상태여야 합니다." + MicroG 설정 + + 구간 카테고리를 선택해주세요 + "선택된 구간은 %02d:%02d부터 %02d:%02d까지 입니다 (%d분 %02d초) +이렇게 제출할까요?" + 시간이 정확한가요? + "설정에서 이 카테고리를 사용하지 않았으며, 제출하려면 다시 사용 설정해야 합니다." + 구간의 시점이나 종점을 편집하고 싶으신가요? + 잘못된 시간 형식입니다. + 완료했어요 + 직접 시간 구간 편집하기 + + 먼저 재생 바에 시작 지점과 끝 지점을 표시해주세요 + 시작 + %02d:%02d:%04d을 구간의 시점 또는 종점으로 설정할까요? + 현재 + 구간의 종점 + 구간의 종점이 설정되었습니다. + 구간의 시점 + 구간의 시점이 설정되었습니다. + 새 SponsorBlock 구간 + 초기화 + 광고 관련 설정입니다. + 광고 설정 + 검색 결과에서 앨범 카드를 보여줍니다. + 검색 결과에서 앨범 카드를 숨깁니다. + 앨범 카드 제거 + 뉴스 속보 선반을 보여줍니다. + 뉴스 속보 선반을 숨깁니다. + 뉴스 속보 선반 제거 + 홈 화면 광고를 보여줍니다. + 홈 화면 광고를 숨깁니다. + 홈 화면 광고 제거 + 채널 가이드라인을 보여줍니다. + 채널 가이드라인을 숨깁니다. + 채널 가이드라인 제거 + 챕터 티저를 보여줍니다. + 챕터 티저를 숨깁니다. + 영상 하단 챕터 티저 제거 + 커뮤니티 가이드라인을 보여줍니다. + 커뮤니티 가이드라인을 숨깁니다. + 커뮤니티 가이드라인 제거 + 커뮤니티 게시물을 보여줍니다. + 커뮤니티 게시물을 숨깁니다. + 커뮤니티 게시물 제거 + 영상 하단 정보 패널을 보여줍니다. + 영상 하단 정보 패널을 숨깁니다. + 영상 하단 정보 패널 제거 + 쉼표로 구분된 이름으로 컴포넌트 필터링 + 사용자 정의 필터 + 긴급 정보 패널을 보여줍니다. + 긴급 정보 패널을 숨깁니다. + 긴급 정보 패널 제거 + 일반 레이아웃 광고를 보여줍니다. + 일반 레이아웃 광고를 숨깁니다. + 일반 레이아웃 광고 제거 + 이미지 선반을 보여줍니다. + 이미지 선반을 숨깁니다. + 이미지 선반 제거 + 정보 패널을 보여줍니다. + 정보 패널을 숨깁니다. + 정보 패널 제거 + 설문 조사를 보여줍니다. + 설문 조사를 숨깁니다. + 설문 조사 제거 + 최신 게시물을 보여줍니다. + 최신 게시물을 숨깁니다. + 최신 게시물 제거 + 의학 정보 패널을 보여줍니다. + 의학 정보 패널을 숨깁니다. + 의학 정보 패널 제거 + 상품 배너를 보여줍니다. + 상품 배너를 숨깁니다. + 상품 배너 제거 + 영화 선반을 보여줍니다. + 영화 선반을 숨깁니다. + 영화 선반 제거 + 검색 결과에서 공식 카드를 보여줍니다. + 검색 결과에서 공식 카드를 숨깁니다. + 공식 카드 제거 + 유료광고 포함 라벨을 보여줍니다. + 유료광고 포함 라벨을 숨깁니다. + 유료광고 포함 라벨 제거 + 셀프 스폰서 카드를 보여줍니다. + 셀프 스폰서 카드를 숨깁니다. + 셀프 스폰서 카드 제거 + 회색 구분 기호를 보여줍니다. + 회색 구분 기호를 숨깁니다. + 회색 구분 기호 제거 + 제안 섹션을 보여줍니다. + 제안 섹션을 숨깁니다. + 제안 섹션 제거 + 실시간 이모티콘 리액션을 보여줍니다. + 실시간 이모티콘 리액션을 숨깁니다. + 실시간 이모티콘 리액션 제거 + 사용자 필터를 비활성화합니다. + 사용자 필터를 활성화합니다. + 사용자 필터 활성화 + 제품 쇼핑 배너를 보여줍니다. + 제품 쇼핑 배너를 숨깁니다. + 제품 쇼핑 배너 제거 + 웹 검색 패널을 보여줍니다. + 웹 검색 패널을 숨깁니다. + 웹 검색 패널 제거 + 플레이어가 버퍼링할 영상의 최대 길이 + 최대 버퍼 설정 + 영상을 일시정지한 후 다시 재생하기 전에 미리 버퍼링할 영상의 길이 + 일시정지후 버퍼링 + 영상 재생 중 버퍼링이 필요할 때 미리 가져올 영상의 길이 + 재버퍼링 + 동영상 버퍼 관련 설정입니다. + 동영상 버퍼 설정 + 모바일 데이터를 사용 중일 때의 기본 영상 화질을 선택합니다. + 모바일 데이터 기본 영상 화질 + Wi-Fi를 사용 중일 때의 기본 영상 화질을 선택합니다. + Wi-Fi 연결 시 기본 영상 화질 + 영상의 기본 재생 속도를 설정합니다. + 기본 영상 재생 속도 + 가 설치되지 않았습니다. 다운로더를 설치해 주세요. + "NewPipe나 PowerTube와 같은 다운로더의 패키지명을 입력하세요." + 다운로더 패키지명 + 다운로더를 설정합니다. + 다운로더 설정 + 추천 영상 오버레이를 보여줍니다. + 추천 영상 오버레이를 숨깁니다. + 추천 영상 오버레이 제거 + 필름 스트립 오버레이를 보여줍니다. + 필름 스트립 오버레이를 숨깁니다. + 필름 스트림 오버레이 제거 + 자동 반복 기능이 꺼져 있습니다. + 자동 반복 기능이 켜져 있습니다. + 영상 자동 반복 + 플레이어 컨트롤이 표시되었을 때 스와이프 제스처를 비활성화합니다. + 플레이어 컨트롤의 표시 여부에 관계없이 항상 스와이프 제스처 활성화합니다. + 스와이프 제스처 항상 활성화 + 사용자 정의 재생 속도를 사용하지 않습니다. + 사용자 정의 재생 속도를 사용합니다. + 사용자 정의 재생 속도 + 외부 브라우저를 사용하지 않습니다. + 외부 브라우저를 사용합니다. + 외부 브라우저 활성화 + HDR 영상 밝기가 기기의 현재 밝기로 자동 설정됩니다. + HDR 영상 밝기가 최대로 자동 설정됩니다. + HDR 영상 최대 밝기 설정 + 백그라운드 재생을 비활성화합니다. + 백그라운드 재생을 활성화합니다. + 백그라운드 재생 + YouTube 레이아웃이 Google 계정 상태를 따라갑니다. + YouTube 버전을 속여서 이전 레이아웃을 강제로 활성화합니다. + 이전 레이아웃 활성화 + 기본 동영상 품질 설정을 사용합니다. + 이전 동영상 품질 설정을 사용합니다. + 품질 설정 스타일 + 영상 설명의 URL을 열 때 URL 리다이렉션(youtube.com/redirect)을 사용합니다. + 영상 설명의 URL을 열 때 URL 리다이렉션(youtube.com/redirect)을 거치지 않고 다이렉트로 연결됩니다. + diff --git a/src/main/resources/youtube/translations/pl-rPL/strings.xml b/src/main/resources/youtube/translations/pl-rPL/strings.xml new file mode 100644 index 000000000..21810fa57 --- /dev/null +++ b/src/main/resources/youtube/translations/pl-rPL/strings.xml @@ -0,0 +1,507 @@ + + + O aplikacji + Ta aplikacja używa API od SponsorBlock + Dotknij, aby dowiedzieć się więcej i zobacz jak pobrać na inne platformy na stronie: sponsor.ajay.app + Integracja wykonana przez JakubWeg + Link API został zmieniony + Podany adres API jest nieprawidłowy + Zresetuj adres API + Alternatywny adres API został zmieniony + Podany alternatywny adres API jest nieprawidłowy + Zresetuj alternatywny adres API + Szukasz zmiany kolorów? + "Teraz możesz zmienić kolor kategorii, klikając na nią powyżej." + Kolor został zmieniony + Nieprawidłowy kod hex + Zresetuj kolor + Jak traktować różne typy segmentów + Włącz SponsorBlock + SponsorBlock to system pomijania denerwujących fragmentów w filmach na YouTube + Włącz alternatywny SponsorBlock + Kiedy serwer API SponsorBlock nie działa, przełącz alternatywny serwer API na domyślny serwer API + Włącz dodawanie nowych segmentów + Włącz to, aby włączyć eksperymentalne dodawanie segmentów (ma problemy z widocznością przycisków) + Włącz ocenianie + Włącz, aby oceniać segmenty. + Główne + Liczba milisekund, którą można przewinąć za pomocą przycisków regulacji czasu, podczas dodawania nowego segmentu + Zmień adres API + "Adres SponsorBlock jest używany do wykonywania połączeń z serwerem. <b>Nie zmieniaj tego, chyba że wiesz, co robisz.<b>" + Zmień adres alternatywnego API + "Adres serwera alternatywnego, gdy serwer SponsorBlock nie działa. <b>Nie zmieniaj tego, chyba że wiesz, co robisz.</b>" + Minimalny czas segmentu + Segmenty krótsze niż ustawiona wartość (w sekundach) nie będą pomijane ani pokazywane w odtwarzaczu + Śledzenie ilości pominięć + To pozwala systemowi wyników SponsorBlock wiedzieć, ile czasu oszczędzili ludzie. To rozszerzenie wysyła wiadomość do serwera za każdym razem, gdy pomijasz segment + Pokaż komunikat podczas automatycznego pomijania segmentu + Kliknij, aby zobaczyć przykładowy komunikat + Pokaż czas bez segmentów + Ten czas pojawia się w nawiasach obok aktualnego czasu. Pokazuje całkowity czas trwania filmu, odejmując wszystkie segmenty. + Twój unikalny identyfikator użytkownika + To powinno być zachowane prywatnie. To jest jak hasło i nie powinno być dzielone z nikim. Jeśli ktoś to posiada, mogą podszywać się pod ciebie + Proszę zainstalować MicroG + MicroG nie został znaleziony + Ustawienia powiadomień + "1. Rejestracja urządzenia Google i Cloud Messaging muszą być włączone dla powiadomień. +2. ReVanced musi być widoczne jako zarejestrowane w Cloud Messaging. +3. Cloud Messaging musi być połączony." + Ustawienia MicroG + minuty + Wybierz kategorię segmentu + "Segment trwa od %02d:%02d do %02d:%02d (%d minut %02d sekund) Czy jest gotowy do wysłania?" + Czy te czasy są poprawne? + "Wyłączyłeś tę kategorię w ustawieniach, włącz ją, aby móc wysłać" + Czy chcesz edytować czas rozpoczęcia lub zakończenia segmentu? + Wprowadzono czas w złym formacie + Gotowe + Edytuj ręcznie czas segmentu + zakończ + Najpierw zaznacz dwie lokalizacje na pasku czasu + rozpocznij + Ustawić %02d:%02d:%04d jako początek czy koniec nowego segmentu? + teraz + Nowy segment SponsorBlock + Zresetuj + Ustawienia dotyczące reklam + Ustawienia reklam + Pokazywane są pułki z bieżącymi wiadomościami + Pułki z bieżącymi wiadomościami są ukryte + Ukryj pułki z bieżącymi wiadomościami + Pokazywane są reklamy z przyciskami + Reklamy z przyciskami są ukryte + Ukryj reklamy z przyciskami + Pokazywane są zasady kanałów + Zasady kanałów są ukryte + Ukryj zasady kanałów + Pokazywane są teasery rozdziałów + Teasery rozdziałów są ukryte + Podgląd rozdziałów pod odtwarzaczem + Pokazywane są zasady + Zasady są ukryte + Ukryj zasady + Pokazywane są posty + Posty są ukryte + Ukryj posty + Pokazywane są kompaktowe banery + Kompaktowe banery są ukryte + Ukryj kompaktowe banery + Filtruj komponenty według ich nazw oddzielonych przecinkiem + Własny filtr + Pokazywane są ramki alarmowe + Ramki alarmowe są ukryte + Ukryj ramki alarmowe + Ogólne reklamy są wyświetlane + Ogólne reklamy są ukryte + Ukryj ogólne reklamy + Pokazywane są półki z obrazkami + Półki z obrazkami są ukryte + Ukryj półki z obrazkami + Wyświetlane są panele informacyjne + Panele informacyjne są ukryte + Ukryj panele informacyjne + Wyświetlane są ankiety + Ankiety są ukryte + Ukryj ankiety + Pokazywane są panele medyczne + Panele medyczne są ukryte + Ukryj panele medyczne + Pokazywane są pułki z filmami + Pułki z filmami są ukryte + Ukryj pułki z filmami + Pokazywane są oficjalne karty w wynikach wyszukiwań + Oficjalne karty w wynikach wyszukiwań są ukryte + Ukryj oficjalne karty + Pokazywane są płatne treści + Płatne treści są ukryte + Ukryj płatne treści + Pokazywane są karty z autopromocją + Karty z autopromocją są ukryte + Ukryj karty z autopromocją + Pokazywane są szare separatory + Szare separatory są ukryte + Ukryj szare separatory + Pokazywane są sugestie + Sugestie są ukryte + Ukryj sugestie + Pokazywane są reakcje przypisane do czasu + Reakcje przypisane do czasu są ukryte + Ukryj reakcje przypisane do czasu + Własny filtr jest wyłączony + Własny filtr jest włączony + Włącz własny filtr + Pokazywane są banery produktów + Banery produktów są ukryte + Ukryj banery produktów + Maksymalny czas trwania wideo, który odtwarzacze będzie próbować pobrać + Maksymalny rozmiar bufora + Długość wideo, jaka musi być zbuforowana, by odtwarzanie rozpoczęło się lub wznowiło po akcji użytkownika takiej jak przewijanie + Początkowy rozmiar bufora + Czas trwania wideo, które muszą być zbuforowane, aby odtwarzanie zostało wznowione po rebuforowaniu + Rozmiar rebufora + Ustawienia związane z rozmiarami bufora wideo + Ustawienia bufora wideo + Wybierz preferowaną rozdzielczość wideo na danych komórkowych + Preferowana jakość wideo dla sieci mobilnej + Wybierz preferowaną rozdzielczość wideo dla Wi-Fi + Preferowana jakość wideo dla Wi-Fi + Wybierz preferowaną prędkość wideo + Domyślna prędkość wideo + nie jest zainstalowany. Zainstaluj go. + Ustawienia związane z domyślną aplikacją do pobierania + Ustawienia aplikacji do pobierania + Wyłącz wibracje + Wibracja podczas powiększenia wideo jest włączona + Wibracja podczas powiększenia wideo jest wyłączona + Wyłącz wibracje podczas powiększania wideo + Link wideo z czasem został skopiowany do schowka + Zawsze odtwarzaj ponownie jest wyłączone + Zawsze odtwarzaj ponownie jest włączone + Zawsze odtwarzaj ponownie + Wyłącz możliwość przesuwania, gdy wyświetlane są ustawienia odtwarzacza + Zawsze umożliwiaj przesuwanie niezależnie od widocznych ustawień odtwarzacza + Włącz przesuwanie + Niestandardowa prędkość wideo jest wyłączona + Niestandardowa prędkość wideo jest włączona + Włącz niestandardową prędkość wideo + Zewnętrzna przeglądarka jest wyłączona + Zewnętrzna przeglądarka jest włączona + Włącz zewnętrzną przeglądarkę + Automatyczna jasność HDR jest wyłączona + Automatyczna jasność HDR jest włączona + Włącz automatyczną jasność HDR + Zminimalizowane odtwarzanie jest wyłączone + Zminimalizowane odtwarzanie jest włączone + Włącz zminimalizowane odtwarzanie + Wygląd YouTube będzie zgodny ze statusem Twojego konta Google + Oszukaj YouTube, aby wymusić włączenie starego wyglądu + Włącz stary wygląd + Wyświetlany jest nowy styl zmieniania jakości + Stary styl zmieniania jakości jest wyświetlany + Włącz stary styl zmieniania jakości + Przekierowywanie URL (youtube.com/redirect) jest używane podczas otwierania linków w opisach + Pomiń przekierowywanie URL (youtube.com/redirect) podczas otwierania linków w opisach + Włącz bezpośrednie otwieranie linków + Naciśnij, by przesunąć jest wyłączone + Naciśnij, by przesunąć jest włączone + Włącz, naciśnij, by przesunąć + Oszukuje dpi, aby użyć niektórych układów telefonów + Włącz układ telefonu + Nie zapisuje preferowanej jakości wideo nawet przy zmianie jakości + Zapisz wybraną jakość wideo jako preferowaną za każdym razem gdy ją zmienisz + Włącz zapisywanie jakości wideo + Nawet jeśli jasność jest ustawiona na 0, przesuwając palcem, automatyczna jasność nie jest włączana + Jeśli jasność jest ustawiona na 0, przesuwając palcem, automatyczna jasność jest włączana + Włącz automatyczną jasność przesuwając palcem + Zmienianie jasności przesuwaniem jest wyłączone + Zmienianie jasności przesuwaniem jest włączone + Włącz zmienianie jasności przesuwaniem + Naciśnij, by przesunąć jest wyłączone + Naciśnij, by przesunąć jest włączone + Włącz naciskanie, by przesunąć + Zmienianie głośności przesuwaniem jest wyłączone + Zmienianie głośności przesuwaniem jest włączone + Włącz zmienianie głośności przesuwaniem + Miniodtwarzacz tabletowy jest wyłączony + Miniodtwarzacz tabletowy jest włączony + Włącz miniodtwarzacz tabletowy + Szeroki pasek wyszukiwania jest wyłączony + Szeroki pasek wyszukiwania jest włączony + Włącz szeroki pasek wyszukiwania + Flagi eksperymentalne + Zgłoś problemy lub zostaw sugestie tutaj + Centrum Problemów ReVanced Extended + Ustawienia ReVanced Extended + Ustawienia powiązane z wersją Extended + Ustawienia wersji Extended + Napisy są włączone, gdy są one wymuszone + "Napisy są wyłączone, gdy są one wymuszone" + Ukryj automatyczne napisy + Pokazywane są automatycznie wyskakujące panele odtwarzacza + Automatycznie wyskakujące panele odtwarzacza są ukryte + Ukryj automatycznie wyskakujące panele odtwarzacza + Pokazywane są przyciski automatycznego odtwarzania + Przyciski automatycznego odtwarzania są ukryte + Ukryj przyciski automatycznego odtwarzania + Ukrywa wybrane przyciski + Ukryj wybrane przyciski + Pokazywane są przyciski do tworzenia klipów + Przyciski do tworzenia klipów są ukryte + Ukryj przyciski do tworzenia klipów + Pokazywane są przyciski łapki w dół + Przyciski łapki w dół są ukryte + Ukryj przyciski łapki w dół + Pokazywane są przyciski pobierania + Przyciski pobierania są ukryte + Ukryj przycisk pobierania + Pokazywane są przyciski łapki w górę + Przyciski łapki w górę są ukryte + Ukryj przyciski łapki w górę + Pokazywane są przyciski czatu na żywo + Przyciski czatu na żywo są ukryte + Ukryj przyciski czatu na żywo + Pokazywane są przyciski playlist + Przyciski playlist są ukryte + Ukryj przyciski playlist + Pokazywane są przyciski do zgłaszania + Przyciski do zgłaszania są ukryte + Ukryj przyciski do zgłaszania + Pokazywane są przyciski do udostępniania + Przyciski do udostępniania są ukryte + Ukryj przyciski do udostępniania + Pokazywane są przyciski do dziękowania + Przyciski do dziękowania są ukryte + Ukryj przyciski do dziękowania + Pokazywane są przyciski do napisów + Przyciski do napisów są ukryte + Ukryj przyciski do napisów + Pokazywany jest przycisk do powielania + Przycisk do powielania jest ukryty + Ukryj przycisk do powielania + Pokazywane są znaki wodne kanałów + Znaki wodne kanałów są ukryte + Ukryj znaki wodne kanałów + Komentarze są pokazywane + Komentarze są ukryte + Ukryj komentarze + Pokazywany jest przycisk do przesyłania + Przycisk do przesyłania jest ukryty + Ukryj przycisk do przesyłania + Pokazywane są ramki ze zbiórkami + Ramki ze zbiórkami są ukryte + Ukryj ramki ze zbiórkami + Pokazywany jest adres email + Adres email jest ukryty + Ukryj adres email + Pokazywane są przyciski w trybie pełnoekranowym + Przyciski w trybie pełnoekranowym są ukryte + Ukryj przyciski w trybie pełnoekranowym + Pokazywane są karty z informacjami + Karty z informacjami są ukryte + Ukryj karty z informacjami + Pokazywane jest menu trybu otoczenia + Menu trybu otoczenia jest ukryte + Ukryj menu trybu otoczenia + Pokazywane jest menu ścieżki audio + Menu ścieżki audio jest ukryte + Ukryj menu ścieżki audio + Pokazywane jest menu napisów + Menu napisów jest ukryte + Ukryj menu napisów + Pokazywane jest menu sterowania słuchaniem + Menu sterowania słuchaniem jest ukryte + Ukryj menu sterowania słuchaniem + Pokazywane jest menu słuchania używając YouTube Music + Menu słuchania używając YouTube Music jest ukryte + Ukryj menu słuchania używając YouTube Music + Pokazywane jest menu pętli wideo + Menu pętli wideo jest ukryte + Ukryj menu pętli wideo + Pokazywane jest menu z większą ilością informacji + Menu z większą ilością informacji jest ukryte + Ukryj menu z większą ilością informacji + Pokazywane jest menu zgłaszania + Menu zgłaszania jest ukryte + Ukryj menu zgłaszania + Pokazywane jest menu ze statystykami dla nerdów + Menu ze statystykami dla nerdów jest ukryte + Ukryj menu ze statystykami dla nerdów + Pokazywane jest menu oglądania w VR + Menu oglądania w VR jest ukryte + Ukryj menu oglądania w VR + Pokazywane są playlisty utworzone automatycznie + Playlisty utworzone automatycznie są ukryte + Ukryj playlisty utworzone automatycznie + Pokazywane są wyróżnione komentarze + Wyróżnione komentarze są ukryte + Ukryj wyróżnione komentarze + Pokazywane są półki z relacjami + Półki z relacjami są ukryte + Ukryj półki z relacjami + Pokazywane są sugerowane działania + Sugerowane działania są ukryte + Ukryj sugerowane działania + Pokazywane są czasy i paski oglądania + Czasy i paski oglądania są ukryte + Ukryj czasy i paski oglądania + Ustawienia wyglądu dołu odtwarzacza + Ustawienia wyglądu pełnoekranowego + Ogólne ustawienia wyglądu + Ustawienia wyglądu odtwarzacza + Ustawienia wyglądu paska + Ustawienia dotyczące wyglądu + Ustawienia wyglądu + Różne ustawienia + Inne + Przyciski automatycznego odtwarzania są ukryte + Pokazywane są przyciski automatycznego odtwarzania + Pokaż przyciski automatycznego odtwarzania + Przyciski do kopiowania linków są ukryte + Pokazywane są przyciski do kopiowania linków + Pokaż przyciski do kopiowania linków + Przyciski do kopiowania linków z czasem są ukryte + Pokazywane są przyciski do kopiowania linków z czasem + Pokaż przyciski do kopiowania linków z czasem + Przyciski do pobierania są ukryte + Pokazywane są przyciski do pobierania + Pokaż przyciski do pobierania + Przyciski białej listy są ukryte + Pokazywane są przyciski białej listy + Pokaż przyciski białej listy + Obecne Logo: Domyślne + Obecne Logo: Premium + Logo Premium + Informacje o zastosowanych łatkach + Informacje o łatkach + "Ponieważ jest to funkcja eksperymentalna, mogą pojawić się inne problemy. +Czy na pewno chcesz kontynuować?" + "Oszukuję YouTube, że używasz wersji v17.28.35, aby używać starego wyglądu + +W ustawieniach aplikacji wersja YouTube może być oznaczona jako v17.28.35" + "Oszukuje dpi, aby zmienić niektóre układy na układy telefonów. + +Jeśli włączysz to ustawienie, dostępne będą następujące funkcje: +- Posty +- Ukrywanie automatycznie stworzonych playlist" + "Oszukuje dpi, aby zmienić niektóre układy na układy tabletów. + +Jeśli włączysz to ustawienie, następujące funkcje nie będą dostępne: +- Tryb otoczenia +- Posty" + Dane o łapkach w dół są dostarczane przez True RYD Worker API. Dotknij tutaj by dowiedzieć się więcej. + ture-ryd.cane.workers.dev + Alternatywne API jest wyłączone + Alternatywne API jest włączone + Włącz alternatywne API + "API True RYD Worker używa liczby łapek w dół z Końcowego Punktu YouTube API. + +Włącz tę opcję tylko, jeżeli doświadczasz problemów podczas używania domyślnego RYD API. + +Czy chcesz kontynuować?" + True RYD Worker + Dane o łapkach w dół są dostarczane przez True RYD Worker API. Dotknij tutaj by dowiedzieć się więcej. + ReturnYouTubeDislike.com + Łapki w dół pokazane jako liczba + Łapki w dół pokazane jako procent + Łapki w dół jako procent + Łapki w dół nie są pokazywane + Łapki w dół są pokazywane + Return YouTube Dislike + Łapki w dół nie są dostępne (limit API użytkownika został osiągnięty) + ReturnYouTubeDislike nie potwierdził nowego użytkownika + ReturnYouTubeDislike nie potwierdził głosu + Łapki w dół są tymczasowo niedostępne (API nie reaguje) + ReturnYouTubeDislike nie zajerestrowało łapki w dół + Ustawania Return YouTube Dislike + Return YouTube Dislike + Ustawienia ReVanced + Ustawienia związane z przesuwaniem + Ustawienia przesuwania + Wysokość, na której ma działać przesuwanie + użyte narzędzie + Pokazywane są reklamy podczas wideo + Reklamy podczas wideo są ukryte + Ukryj reklamy podczas wideo + Nie udało się zmienić jakości obrazu + Brak połączenia z internetem + Zmiana domyślnej jakości podczas korzystania z danych komórkowych na: + Nie udało się zmienić domyślnej jakości podczas korzystania z danych komórkowych + Zmiana domyślnej jakości podczas korzystania z sieci Wi-Fi na: + Nie udało się zmienić domyślnej jakości podczas korzystania z WI-FI + Ustawienia dotyczące wideo + Ustawienia wideo + Nie udało się dodać kanału %s do białej listy %s + Kanał %s został dodany do białej listy %s + Reklamy Wideo + Reklamy + Nazwa Kanału + Brak kanałów na białej liście + Nie dodano do białej listy + Dodano do białej listy + Biała Lista Kanałów + Nie udało się uzyskać szczegółów kanału, otrzymany kod %d + Uruchom ponownie aby zastosować ustawienia białej listy kanałów + Nie udało się usunąć kanału %s z białej listy %s + Kanał %s został usunięty z białej listy %s + Ustawienia białej listy + Szybkość Wideo + Szybkość + SponsorBlock + SB + Serwer SponsorBlocka nie odpowiada! + Już przeczytane + "Zalecane jest przeczytanie regulaminu SponsorBlocka przed wysłaniem jakiegokolwiek segmentu" + Pokaż mi + Istnieją zasady + Zasady zawierają porady i zasady dotyczące wysyłania segmentów + Zobacz zasady + Ustawienia SponsorBlocka + Ustawienia dotyczące SponsorBlocka + Przełączono pomyślnie. odśwież wideo + Przełączanie serwera alternatywnego API na główny serwer API.. + Nietematyczny Wypełniacz/Żart + Przerwa/Animacja Intra + Fragment bez zawartości. Może być pauzą, statyczną klatką obrazu lub powtarzającą się animacją + Muzyka: Sekcja niemuzyczna + Zapowiedź/Podsumowanie + "Podsumowanie poprzednich odcinków lub zapowiedź tego, co pojawi się później w bieżącym wideo lub przyszłych wideo z tej samej serii. Klipy nie powinny dostarczać dodatkowych informacji." + Nieopłacona/Własna Promocja + Niepłatne promocje lub autopromocje. Obejmuje to sekcje o własnych produktach, dotacjach lub informacjach o tym, z kim współpracowali + Sponsor + Płatne promocje, płatne rekomendacje i bezpośrednie reklamy + Przypomnienia o interakcji (Subskrybuj) + Kiedy pojawia się krótkie przypomnienie, aby polubić, zasubskrybować, śledzić lub wejść w interakcję z nimi na dowolnej darmowej lub płatnej platformie + Nie udało się wyeksportować ustawień + Importuj/Eksportuj ustawienia + To jest cała twoja konfiguracja, która ma zastosowanie w rozszerzeniu komputerowy w formacie JSON. Obejmuje to twoje prywatne ID użytkownika, więc upewnij się, że udostępniasz to ostrożnie. + Nie udało się zaimportować ustawień + Ustawienia zostały pomyślnie zaimportowane + Pomiń automatycznie + Pomiń automatycznie jeden raz + "Nie rób nic" + Pokaż przycisk do pomijania + Pomiń segment + Pominięto zakończenie + Pominięto wypełniacz + Pominięto wstęp + Pominięto sekcję niemuzyczną + Pominięto segment sponsorowany + Pominięto autopromocje + Pominięto treści sponsorowane + Pominięto irytujące przypomnienie + Pominięto niezgłoszony segment + Statystyki + Ładowanie.. + "Uchroniłeś ludzi przed <b>%s</b> segmentami." + "To <b>%s</b> ich życia. Kliknij, aby zobaczyć tablicę wyników" + SponsorBlock jest wyłączony + "Pominięto <b>%s</b> segmentów." + "To jest <b>%s</b>." + Ilość zgłoszeń: <b>%s</b> + Twoja nazwa użytkownika: <b>%s</b> + Kliknij, aby zmienić nazwę użytkownika + Nie można zmienić nazwy użytkownika: Status: %d %s + Nazwa użytkownika została zmieniona + "Nie można wysłać segmentu. On już istnieje" + "Nie można wysłać segmentu + +%s" + "Nie można wysłać segmentu (zbyt wiele od tego samego użytkownika lub IP)" + Nie można wysłać segmentu: %s + Nie można wysłać segmentów: Status: %d %s + Wysyłanie segmentu… + Segment został wysłany pomyślnie + Dotknij, aby pominąć + Zmień kategorię + Głos przeciw + "Nie można zagłosować na segment + +%s" + "Nie można zagłosować na segment. +Przekroczono limit głosów (od tego samego użytkownika lub IP)" + Nie można zagłosować na segment: Status: %d %s + Brak segmentów, na które można zagłosować + Głosowanie na segment… + Pomyślnie zagłosowano + Głos za + diff --git a/src/main/resources/youtube/translations/pt-rBR/strings.xml b/src/main/resources/youtube/translations/pt-rBR/strings.xml new file mode 100644 index 000000000..3b38aec62 --- /dev/null +++ b/src/main/resources/youtube/translations/pt-rBR/strings.xml @@ -0,0 +1,101 @@ + + + Sobre + Esse aplicativo usa a API do SponsorBlock + Toque para saber mais, e veja os downloads para outras plataformas em: sponsor.ajay.app + Integração feita por JakubWeg + Ativar os controles de acessibilidade para o player de vídeo? + Seus controles foram modificados porque um serviço de acessibilidade está ativado. + URL da API alterada + URL da API fornecida é inválida + URL da API foi Redefinida + API MIRROR URL alterada + A URL de API forcecida é inválida + API MIRROR URL alterada + Você está procurando por como mudar as cores? + "Agora você pode alterar a cor de uma categoria clicando nela acima." + Cor alterada + Código hex inválido + Redefinição de cor + O que fazer com diferentes segmentos + Ativar Sponsorblock + SponsorBlock é um sistema comunitário para pular partes irritantes em vídeos do YouTube + Ativar SponsorBlock (Beta) + Quando o servidor API do SponsorBlock for retirado, mude o servidor de API espelhado para servidor API padrão + Habilitar envio de novos segmentos + Ative isto para habilitar o envio de segmento experimental (tem problemas de visibilidade do botão) + Habilitar votação + Ative isto para habilitar a votação. + Geral + Ajustando novo passo de segmento + Este é o número de milissegundos que você pode mover quando usa os botões de ajuste de tempo ao adicionar um novo segmento + Alterar URL da API + "O endereço que o SponsorBlock usa para requisitar dados ao servidor. <b>Não altere isso a menos que você saiba o que está fazendo.</b>" + Alterar URL da API Mirror + "Espelhar endereço do servidor para onde mudar quando o servidor do Patrocinador for derrubado. <b>Não mude isso a menos que você saiba o que está fazendo.</b>" + Duração mínima do segmento + Segmentos menores que o valor definido (em segundos) não serão ignorados ou exibidos no player + Contagem de segmentos pulados + Permite que o sistema do SponsorBlock saiba quanto tempo as pessoas economizaram. A extensão envia uma mensagem pro servidor sempre que você pula um segmento + Mostrar um aviso quando pular um segmento automaticamente + Toque para ver um exemplo de aviso + Mostrar tempo sem segmentos + Este tempo aparece entre parênteses ao lado do tempo atual. Isso mostra a duração total do vídeo menos os segmentos. + Seu id único de usuário + Isto deve permanecer privado. É uma espécie de senha e não deve ser compartilhado. Caso alguém a possua, é possível se passar por você + Por favor, instale o MicroG + O microG não foi encontrado + Configurações de notificação + "1. O registro do dispositivo do Google e o Cloud Messaging precisam ser ativados para as notificações. +2. Reforço precisa ser mostrado como registrado na Cloud Messaging. +3. A atual estado no Cloud Messaging deve ser conectada." + Configurações do MicroG + minutos + Escolha a categoria do segmento + "O segmento dura de %02d:%02d até %02d:%02d (%d minutos %02d segundos)\nEle está pronto para enviar?" + Os tempos estão corretos? + "Você desativou esta categoria nas configurações, habilite-a para poder enviar" + Você deseja editar o tempo para o início ou o fim do segmento? + Tempo inserido inválido + Concluído + Editar tempo do segmento manualmente + fim + Marcar dois locais na barra de tempo primeiro + Inicio + Definir %02d:%02d:%04d como início ou fim de um novo segmento? + agora + Tempo que o segmento termina em + Fim do seguimento definido + Tempo que o segmento começa em + Início do segmento definido + Novo segmento SponsorBlock + Redefinir + Os cartões de álbum são mostrados nos resultados de pesquisa + Os cartões de álbum estão ocultos dos resultados da pesquisa + Ocultar capa do álbum + Painéis de notícias de última hora são mostrados + Painéis de notícias de última hora são mostrados + Ocultar a última estante de notícias + Anúncios na tela inicial serão exibidos + Anúncios na tela inicial serão exibidos + Ocultar anúncio com botão + Diretrizes do canal são mostradas + Diretrizes do canal estão ocultas + Ocultar diretrizes do canal + Teasers de capítulo são exibidos + Teasers de capítulo estão ocultos + Ocultar separador cinza + Sugestões são exibidas + Sugestões estão ocultas + Ocultar sugestões + Reações com tempo são mostradas + Reações com tempo estão ocultas + Ocultar reações com tempo + Filtro de usuário está desativado + Filtro de usuário está habilitado + Ativar filtro de usuário + Exibir o banner de produtos + Banner de produtos está oculto + Ocultar visualização de banner de produtos + Os painéis de pesquisa da web são mostrados + diff --git a/src/main/resources/youtube/translations/ru-rRU/strings.xml b/src/main/resources/youtube/translations/ru-rRU/strings.xml new file mode 100644 index 000000000..13e2185be --- /dev/null +++ b/src/main/resources/youtube/translations/ru-rRU/strings.xml @@ -0,0 +1,618 @@ + + + О нас + Это приложение использует API от SponsorBlock + Нажмите, чтобы узнать больше и посмотреть загрузки на другие платформы: sponsor.ajay.app + Автор интеграции - JakubWeg + Включить специальные возможности для видеоплейера? + Управление изменено, поскольку служба специальных возможностей включена. + API URL изменен + Предоставленный API URL недействителен + Сбросить API URL + Зеркальный адрес API изменён + Предоставленное зеркало API URL недействительно + Зеркальный адрес API сброшен + Вы хотите изменить цветовую тему? + "Теперь вы можете изменить цвет категории, нажав на неё выше." + Цвет изменён + Недействительный шестнадцатеричный (hex) код + Сброс цвета + Действия с различными сегментами + Включить SponsorBlock + SponsorBlock - краудсорсинговая система для пропуска раздражающих частей в видео на YouTube + Включить зеркало SponsorBlock + Когда сервер API SponsorBlock отключен, переключите зеркальный сервер API на сервер API по умолчанию + Включить добавление нового сегмента + Включите, чтобы активировать экспериментальное добавление сегментов (имеются проблемы с отображением кнопок) + Включить голосование + Включите, чтобы использовать голосование. + Основные + Настройка шага изменения времени сегмента + Количество миллисекунд, на которое можно сдвигать время во время использования кнопок перемотки при добавлении нового сегмента + Изменить API URL адреса + "Адрес, используемый SponsorBlock для связи с сервером. <b>Не меняйте, если не знаете, что делаете</b>" + Изменить зеркальный API URL + "Зеркальный адрес сервера, когда сервер SponsorBlock не доступен. <b>Не меняйте, если не знаете, что делаете</b>" + Минимальная длительность сегмента + Сегменты, продолжительность которых короче чем установленное значение (в секундах) не будет пропущена или показана в проигрывателе + Подсчёт количества пропусков + Это позволяет системе доски лидеров SponsorBlock знать, сколько времени было сэкономлено. Расширение отправляет сообщение на сервер каждый раз при пропуске сегмента + Показывать уведомление при автоматическом пропуске сегмента + Нажмите, чтобы увидеть пример уведомления + Показывать время без сегментов + Это время будет показано в скобках рядом с текущим временем. Это время показывает продолжительность видео, минус продолжительность сегментов. + Ваш уникальный ID пользователя + Это нужно держать в секрете. Это как пароль, не стоит им ни с кем делиться. Если он у кого-то есть, он сможет выдать себя за Вас + Пожалуйста, установите MicroG + MicroG не найден + Настройки уведомлений + "1. Регистрация устройства в Google и Cloud Messanging должны быть включены для отправки уведомлений. +2. ReVanced должен отображаться как зарегистрированный в Cloud Messaging. +3. Состояние в Cloud Messanging должно быть отображено как \"Подключено\"." + Настройки MicroG + минуты + Выберите категорию сегмента + "Сегмент длится с %02d:%02d до %02d:%02d (%d минут(-ы/-а) %02d секунд(-ы/-а)) +Сегмент готово для отправки?" + Время начала и конца сегмента верно? + "Эта категория отключена в настройках. Включите ее для отправки сегмента" + Вы хотите изменить время начала или окончания сегмента? + Неверное время + Готово + Изменить время сегмента вручную + Конец сегмента + Сначала отметьте два места на шкале времени + Начало сегмента + Установить %02d:%02d:%04d как начало или конец нового сегмента? + cейчас + Время окончания сегмента: + Окончание сегмента установлено + Время начала сегмента: + Начало сегмента установлено + Новый сегмент SponsorBlock + Сброс + Настройки отображения рекламы + Настройки рекламы + Карточки альбомов показаны из результатов поиска + Карточки альбомов скрыты из результатов поиска + Скрыть карточки альбомов + Панель последних новостей отображена + Панель последних новостей скрыта + Скрыть панель последних новостей + Кликабельная реклама на главной странице отображена + Кликабельная реклама на главной странице скрыта + Скрыть кликабельную рекламу + Правила канала отображены + Правила канала скрыты + Скрыть правила канала + Тизер главы под видео отображен + Тизер главы под видео скрыт + Скрыть тизер главы под видео + Правила сообщества отображены + Правила сообщества скрыты + Скрыть правила сообщества + Сообщения сообщества отображены + Сообщения сообщества скрыты + Скрыть сообщения сообщества + Компактные баннеры отображены + Компактные баннеры скрыты + Скрыть компактные баннеры + Фильтровать компоненты по их имени, разделяя их запятыми + Пользовательский фильтр + Экстренные контейнеры отображены + Экстренные контейнеры скрыты + Скрыть экстренные контейнеры + Реклама общего формата отображена + Реклама общего формата скрыта + Скрыть рекламу общего формата + Публикации с изображениями отображены + Публикации с изображениями скрыты + Скрыть публикации с изображениями + Информационные панели отображены + Информационные панели скрыты + Скрыть информационные панели + Опросы в фиде отображены + Опросы в фиде скрыты + Скрыть опросы в фиде + Последние посты отображены + Последние посты скрыты + Скрыть последние посты + Медицинские панели отображены + Медицинские панели скрыты + Скрыть медицинские панели + Баннеры товаров отображены + Баннеры товаров скрыты + Скрыть баннеры товаров + Публикации с фильмами отображены + Публикации с фильмами скрыты + Скрыть публикации с фильмами + Официальные карточки отображены из результатов поиска + Официальные карточки скрыты из результатов поиска + Скрыть официальные карточки + Баннеры платного контента отображены + Баннеры платного контента скрыты + Скрыть баннеры платного контента + Карточки самопродвижения отображены + Карточки самопродвижения скрыты + Скрыть карточки самопродвижения + Серые разделители отображены + Серые разделители скрыты + Скрыть серые разделители + Предложения отображены + Предложения скрыты + Скрыть предложения + Временные реакции отображены + Временные реакции скрыты + Скрыть временные реакции + Пользовательский фильтр выключен + Пользовательский фильтр включен + Включить пользовательский фильтр + Баннер просмотра товаров отображен + Баннер просмотра товаров скрыт + Скрыть баннер просмотра товар + Панели веб-поиска отображены + Панели веб-поиска скрыты + Скрыть панели веб-поиска + Максимальная длительность медиа-файла, который проигрыватель попытается буферизовать + Максимальный размер буфера + Длительность видео, которая должна быть буферизована для начала или продолжения воспроизведения (например, после перемотки) + Размер буфера начала воспроизведения + Длительность медиа-файла, который должен быть буферизирован для воспроизведения после повторной буферизации + Размер повторного буфера + Настройки видео буфера + Настройки видеобуфера + Выбор стандартного разрешение видео (при использовании мобильных сетей) + Разрешение видео по умолчанию (при использовании мобильных сетей) + Выбор стандартного разрешение видео (при использовании Wi-Fi сетей) + Разрешение видео по умолчанию (при использовании Wi-Fi сетей) + Выберите скорость видео по умолчанию + Скорость видео по умолчанию + не установлен. Пожалуйста, установите его. + "Имя пакета приложения-загрузчика видео, например NewPipe или PowerTube" + Имя пакета приложения-загрузчика + Настройки загрузчика по умолчанию + Настройки загрузчика видео + Оверлей в конце видео отображен + Оверлей в конце видео скрыт + Скрыть оверлей в конце видео + Наложение кинопленки отображено + Наложение кинопленки скрыто + Скрыть наложение кинопленки + Вибро-отклик при перемотке включён + Вибро-отклик при перемотке отключён + Отключить вибро-отклик при перемотке + Вибро-отклик при перемотке включён + Вибро-отклик при перемотке отключён + Отключение вибро-отклика при перемотке + Вибро-отклик при смене главы включён + Вибро-отклик при смене главы отключён + Отключить вибро-отклика при смене главы + Отключить вибро-отклик при долгом нажатии + Отключить вибро-отклик + Вибро-отклик при увеличении для заполнения включён + Вибро-отклик при увеличении для заполнения отключён + Отключить вибро-отклик при увеличении для заполнения + Ссылка на видео с тайм-кодом скопирована в буфер обмена + Постоянный автоповтор отключён + Постоянный автоповтор включён + Постоянный автоповтор + Отключить свайп-жесты, когда управление проигрывателем отображено + Включить постоянные свайп-жесты при любом состоянии кнопок контроля плеером + Включить постоянные свайп-жесты + Пользовательская скорость воспроизведения отключена + Пользовательская скорость воспроизведения включена + Включить пользовательскую скорость видео + Внешний браузер отключён + Внешний браузер включён + Использовать внешний браузер + Авто-яркость HDR отключена + Авто-яркость HDR включена + Включить авто-яркость HDR + Воспроизведение в фоне отключено + Воспроизведение в фоне включено + Включить воспроизведение в фоне + Интерфейс YouTube следует статусу Вашего аккаунта + Подменить версию YouTube для включения нового интерфейса + Включить старый интерфейс + Новый стиль выбора качества видео отображён + Старый стиль выбора качества видео отображён + Включить старый стиль отображения качества + URL перенаправление (youtube.com/redirect) используется при открытии ссылок в описаниях видео + Обход URL перенаправления (youtube.com/redirect) при открытии ссылок в описаниях видео + Включить открытые ссылки напрямую + Нажатие для перемотки отключено + Нажатие для перемотки включено + Включить жест нажатия для перемотки + Подменяет DPI для использования интерфейса некоторых телефонов + Включить телефонный интерфейс + Нажатие на строку перемотки отключено + Не сохранять значение качества видео при его изменении + Сохранять значение качества видео при его изменении + Включить сохранение качества видео + Нажатие на строку перемотки включено + Включить нажатие на строку перемотки + Не активировать авто-яркость, если яркость установлена свайпом на 0 + Активировать авто-яркость, если яркость установлена свайпом на 0 + Активировать авто-яркость свайпом + Изменение яркости жестом отключено + Изменение яркости жестом включено + Изменение яркости жестом + Вибро-отклик при нажатии для перемотки отключён + Вибро-отклик при нажатии для перемотки включён + Включить вибро-отклик при нажатии для перемотки + Изменение громкости жестом отключено + Изменение громкости жестом включено + Включить изменение громкости жестом + Планшетный мини-проигрыватель отключён + Планшетный мини-проигрыватель включён + Включить планшетный мини-проигрыватель + Подменяет DPI для использования интерфейса некоторых планшетов + Включить планшетный интерфейс + Широкая панель поиска отключена + Широкая строка поиска включена + Включить широкую строку поиска + Экспериментальные опции + Сообщить о проблемах или оставить предложения здесь + Центр помощи ReVanced Extended + Настройки ReVanced Extended + Настройки связанные с Extended + Настройки Extended + Исправление проблем с буфером воспроизведения видео отключено + Исправление проблем с буфером воспроизведения видео включено + Исправление проблем с буфером воспроизведения видео + Автоматически включить отображение субтитров при их присутствии + "Автоматически отключать отображение субтитров при их присутствии" + Отключить автоматические субтитры + Автоматические всплывающие панели проигрывателя отображены + Автоматические всплывающие панели проигрывателя скрыты + Скрывать автоматические всплывающие панели проигрывателя + Кнопка автовоспроизведения отображена + Кнопка автовоспроизведения скрыта + Скрыть кнопку автовоспроизведения + Скрыть компоненты контейнера кнопок + Скрыть компоненты контейнера кнопок + Кнопка \"Создать клип\" отображена + Кнопка \"Создать клип\" скрыта + Скрыть кнопку \"Создать клип\" + Кнопка \"Создать Short\" отображена + Кнопка \"Создать Short\" скрыта + Скрыть кнопку \"Создать Short\" + Кнопка \"Не нравится\" отображена + Кнопка \"Не нравится\" скрыта + Скрыть кнопку \"Не нравится\" + Кнопка \"Скачать\" отображена + Кнопка \"Скачать\" скрыта + Скрыть кнопку \"Скачать\" + Кнопка \"Нравится\" отображена + Кнопка \"Нравится\" скрыта + Скрыть кнопку \"Нравится\" + Кнопка \"Живой чат\" отображена + Кнопка \"Живой чат\" скрыта + Скрыть кнопку \"Живой чат\" + Кнопка \"Плейлист\" отображена + Кнопка \"Плейлист\" скрыта + Скрыть кнопку \"Плейлист\" + Кнопка \"Пожаловаться\" отображена + Кнопка \"Пожаловаться\" скрыта + Скрыть кнопку \"Пожаловаться\" + Кнопка \"Поделиться\" отображена + Кнопка \"Поделиться\" скрыта + Скрыть кнопку \"Поделиться\" + Кнопка \"Поблагодарить\" отображена + Кнопка \"Поблагодарить\" скрыта + Скрыть кнопку \"Поблагодарить\" + Кнопка субтитров отображена + Кнопка субтитров скрыта + Скрыть кнопку субтитров + Кнопка трансляции на телевизор отображена + Кнопка трансляции на телевизор скрыта + Скрыть кнопку трансляции на телевизор + Водяной знак канала показан + Водяной знак канала скрыт + Скрыть водяной знак канала + Скрывает раздел комментариев или компонент + Скрыть компонент комментариев + Раздел комментариев отображён + Раздел комментариев скрыт + Скрыть раздел комментариев + Кнопка \"Создать\" отображена + Кнопка \"Создать\" скрыта + Скрыть кнопку \"Создать\" + Краудфандинг контейнер отображен + Краудфандинг контейнер скрыт + Скрыть краудфандинг контейнер + Адрес электронной почты отображён + Адрес электронной почты скрыт + Скрыть адрес электронной почты + Карточки в конце видео отображены + Карточки в конце видео скрыты + Скрыть карточки в конце видео + Контейнер кнопки \"Полноэкранный режим\" отображён + Контейнер кнопки \"Полноэкранный режим\" скрыт + Скрыть контейнер кнопки \"Полноэкранный режим\" + Подсказки отображены + Подсказки скрыты + Скрыть подсказки + Меню режима окружающей подсветки отображено + Меню режима окружающей подсветки скрыто + Скрыть меню режима окружающей подсветки + Меню аудио трека отображено + Меню аудио трека скрыто + Скрыть меню аудио трека + Меню субтитров отображено + Меню субтитров скрыто + Скрыть меню субтитров + Меню помощи и отзывов отображено + Меню помощи и отзывов скрыто + Скрыть меню помощи и отзывов + Меню управления прослушиванием отображено + Меню управления прослушиванием скрыто + Скрыть меню управления прослушиванием + Меню \"Слушать с YouTube Music\" отображено + Меню \"Слушать с YouTube Music\" скрыто + Скрыть меню \"Слушать с YouTube Music\" + Меню зацикливания видео отображено + Меню зацикливания видео скрыто + Скрыть меню зацикливания видео + Меню \"Детальнее\" отображено + Меню \"Детальнее\" скрыто + Скрыть меню \"Детальнее\" + Меню жалоб отображено + Меню жалоб скрыто + Скрыть меню жалоб + Меню статистики для сисадминов отображено + Меню статистики для сисадминов скрыто + Скрыть меню статистики для сисадминов + Меню просмотра в VR отображено + Меню просмотра в VR скрыто + Скрыть меню просмотра в VR + Микс плейлиста отображён + Микс плейлиста скрыт + Скрыть микс плейлиста + Фильтр оверлея на проигрыватель отображён + Фильтр оверлея на проигрывателье скрыт + Скрыть фильтр оверлея на проигрывателье + Предпросмотр комментария показан + Предпросмотр комментария скрыт + Скрыть предпросмотр комментария + Кнопка \"Shorts\" отображена + Кнопка \"Shorts\" скрыта + Скрыть кнопку \"Shorts\" + Скрывает раздел \"Shorts\" или компоненты плеера \"Shorts\" + Скрыть компонент \"Shorts\" + Кнопка комментариев плеера \"Shorts\" отображена + Кнопка комментариев плеера \"Shorts\" скрыта + Скрыть кнопку комментариев плеера \"Shorts\" + Скрыть компоненты проигрывателя \"Shorts\" + Кнопка ремикса плеера \"Shorts\" отображена + Кнопка ремикса плеера \"Shorts\" скрыта + Скрыть кнопку ремикса плеера \"Shorts\" + Кнопка подписки плеера \"Shorts\" отображена + Кнопка подписки плеера \"Shorts\" скрыта + Скрыть кнопку подписки плеера \"Shorts\" + Кнопка благодарности плеера \"Shorts\" отображена + Кнопка благодарности плеера \"Shorts\" скрыта + Скрыть кнопку благодарности плеера \"Shorts\" + Полки \"Shorts\" отображены + Полки \"Shorts\" скрыты + Скрыть полки \"Shorts\" + Проигрыватель \"Shorts\" отключен при запуске приложения + Проигрыватель \"Shorts\" включен при запуске приложения + Проигрыватель \"Shorts\" при запуске приложения + Полки \"Сториз\" отображены + Полки \"Сториз\" скрыты + Скрыть полки \"Сториз\" + Предлагаемые действия отображены + Предлагаемые действия скрыты + Скрыть предлагаемые действия + Время и строка перемотки видео отображены + Время и строка перемотки видео скрыты + Скрыть время и строку перемотки видео + Настройки расположения нижнего проигрывателя + Настройки расположения меню Flyout + Настройки расположения полноэкранного просмотра + Общие настройки расположения + Настройки расположения проигрывателя + Настройки расположения строки перемотки + Настройки, связанные с интерфейсом + Насройки интерфейса + Настройки, связанные с прочими параметрами + Прочие параметры + Другие + Кнопка авто-повтора скрыта + Кнопка авто-повтора отображена + Отображать кнопку авто-повтора + Кнопка копирования ссылки на видео скрыта + Кнопка копирования ссылки на видео отображена + Отображать кнопку копирования ссылки на видео + Кнопка копирования ссылки на видео с отметкой времени скрыта + Кнопка копирования ссылки на видео с отметкой времени отображена + Отображать кнопку копирования ссылки на видео с отметкой времени + Кнопка \"Скачать\" скрыта + Кнопка \"Скачать\" отображена + Отображать кнопку \"Скачать\" + Настройки отображения кнопок в проигрывателе + Настройки отображения кнопок + Кнопка \"Белый лист\" скрыта + Кнопка \"Белый лист\" отображена + Отображать кнопку \"Белый лист\" + Текущий заголовок - заголовок по умолчанию (YouTube) + Текущий заголовок - Premium + Заголовок интерфейса + Информация о примененных патчах + Информация о патчах + Cкрывает компонент настройки плеера панели \"Flyout\" + Компонент панели проигрывателя \"Flyout\" + "Поскольку это экспериментальная функция, могут быть неизвестные проблемы. +Вы уверены, что хотите продолжить?" + "Подменяет версию клиента YouTube на v17.28.35 для отображения старого интерфейса + +В настройках приложения YouTube версия может быть отображена как v17.28.35" + "Подменяет DPI для изменения некоторых частей интерфейса на телефонный. + +Если этот параметр включен, следующие функции будут доступны: +- Сообщения сообщества +- Кнопка \"Скрыть плейлист\"" + "Исправление ошибки буфера воспроизведения видео в некоторых регионах. + +Если эта опция включена, может возникнуть следующая проблема: +- При воспроизведении видео в плейлисте проблема не может быть исправлена" + "Подменяет DPI для изменения некоторых частей интерфейса на планшетный. + +Если этот параметр включен, следующие функции будут не доступны: +- Режим окружающей подсветки +- Сообщения сообщества" + Данные \"Не нравится\" предоставляются при помощи True RYD Worker API. Нажмите здесь, чтобы узнать больше. + true-ryd.cane.workers.dev + Зеркало API отключено + Зеркало API включено + Включить зеркало API + "True RYD Worker API использует подсчёт \"Не нравится\" доступный в конечной точке YouTube API. +Как таковой, он менее точен, чем стандартный RYD API. + +Эта опция предназначена только для тех, кто испытывает проблемы при использовании стандартного RYD API. + +Вы уверены, что хотите продолжить?" + True RYD Worker + Данные \"Не нравится\" предоставляются при помощи Return YouTube Dislike API. Нажмите здесь, чтобы узнать больше. + ReturnYouTubeDislike.com + \"Не нравится\" отображаются как число + \"Не нравится\" отображаются как проценты + \"Не нравится\" как проценты + \"Не нравится\" скрыты + \"Не нравится\" отображены + Return YouTube Dislike + \"Не нравится\" не доступны (достигнут лимит клиента API) + ReturnYouTubeDislike не смог подтвердить нового пользователя + ReturnYouTubeDislike не смог подтвердить голосование + \"Не нравится\" временно не доступны (время API истекло) + ReturnYouTubeDislike не смог зарегистрировать нового пользователя + ReturnYouTubeDislike не смог выслать голосование + Настройки Return YouTube Dislike + Return YouTube Dislike + Настройки ReVanced + Настройки, связанные с управления жестами + Настройки управления жестами + Минимальная амплитуда движения, распознаваемого как жест + Порог величины жеста + Видимость фона оверлея при жесте + Видимость фона при жесте + Размер текста наложения при жесте + Размер текста при жесте + Кол-во миллисекунд отображение оверлея + Таймаут наложения при жесте + Использованные инструменты: + Реклама в видео отображена + Реклама в видео скрыта + Скрыть рекламу в видео + Не удалось задать качество видео + Нет подключения к Интернету + Качество видео при просмотре через мобильную сеть: + Не удалось задать качество видео при подключении через мобильную сеть + Качество видео при просмотре через Wi-Fi: + Не удалось задать качество видео при подключении через Wi-Fi + Настройки, связанные с видео + Настройки видео + Не удалось добавить канал %s в белый список %s + Канал %s был добавлен в белый список %s + Реклама в видео + Реклама + Название канала + Каналы в белом списке отсутствуют + Не существует в белом списке + Добавлено в белый список + Белый список каналов + Не удалось получить данные о канале, получен код %d + Необходима перезагрузка приложения, чтобы применить настройки белого списка каналов + Не удалось удалить канал %s из белого списка %s + Канал %s был удален из белого списка %s + Проверить или удалить список каналов, добавленных в белый список + Настройки белого списка + Скорость видео + Скорость + SponsorBlock + SB + Сервер Sponsorblock не отвечает! + Уже готово + "Перед отправкой любого сегмента рекомендуется прочитать рекомендации от SponsorBlock" + Показать + Существуют рекомендации + Руководство содержит советы по отправке сегмента + Посмотреть руководство + Настройки SponsorBlock + Настройки, относящиеся к SponsorBlock + Успешно изменено. Необходима перезагрузка видео + Переключение с зеркального сервера API на основной API сервер... + Конечная заставка/титры + Титры или время появления конечных заставок YouTube. Не для устного подведения итогов, сказанного в видео + Отвлечённые темы/шутки + Сегменты, которые увеличивают длительность видео за счёт отвлечённых тем или шуток, но не требуются для понимания основного содержания. Не должно иметь сегментов, объясняющие контекст или предысторию + Вступительная заставка/анимация + Интервал без фактического содержимого. Может быть паузой, статическим кадром, повторяющейся анимацией + Музыка: Сегмент без музыки + Только для использования в музыкальных видеороликах. Пропускает части видео, отсутствующие в официальных миксах + Предпросмотр/Краткое содержание + "Краткое содержание предыдущих эпизодов или предварительный просмотр того, что будет в данном видео. Предназначено для сегментов, смонтированных из кусков видео, а не для дополнительной информации." + Самореклама/Рекомендация + Похоже на спонсорскую рекламу, но для бесплатной рекламы и саморекламы. Включает в себя вставки про мерчендайз, пожертвования или информацию о тех, вместе с кем было сделано видео + Спонсорская реклама + Рекламные интеграции, реферальные ссылки и прямая реклама + Напоминание о взаимодействии (подписка) + Когда в середине контента есть короткое напоминание поставить лайк и/или подписаться + Не удалось экспортировать настройки + Импорт/Экспорт настроек + Это вся Ваша конфигурация, применимая в расширении для ПК в формате JSON. Сюда входит Ваш идентификатор пользователя, поэтому делитесь им с умом. + Не удалось импортировать настройки + Настройки успешно импортированы + Автоматически пропускать + Автоматически пропускать единожды + "Ничего не делать" + Показывать кнопку пропуска + Пропустить сегмент + Пропущена концовка + Пропущен наполнитель контент (филлер) + Пропущено интро + Пропущен не музыкальный сегмент + Пропущено краткое содержание + Пропущен сегмент спонсорской рекламы + Пропущена самореклама + Пропущена спонсорская реклама + Пропущено назойливое напоминание + Пропущен неотправленный сегмент + Статистика + Загрузка... + "Вы избавили людей от <b>%s</b> сегментов." + "Это <b>%s</b> их жизни. Нажмите, чтобы увидеть таблицу лидеров" + SponsorBlock отключён + "Вы пропустили <b>%s</b> сегментов." + "Это <b>%s</b>" + Отправленные сегменты: <b>%s</b> + Ваше имя пользователя: <b>%s</b> + Нажмите, чтобы изменить имя пользователя + Невозможно изменить имя пользователя: Статус: %d %s + Имя пользователя успешно изменено + "Невозможно отправить сегмент. +Сегмент уже существует" + "Невозможно отправить сегмент. + +%s" + "Не удается отправить сегмент. +Лимит запросов достигнут (слишком много запросов от данного пользователя или IP)" + Не удается отправить сегмент: %s + Не удалось отправить сегменты: Статус: %d %s + Отправка сегмента… + Сегмент успешно отправлен + Нажмите, чтобы пропустить + Изменить категорию + Проголосовать против + "Невозможно проголосовать за сегмент. + +%s" + "Невозможно проголосовать за сегмент. +Лимит запросов достигнут (слишком много запросов от данного пользователя или IP)" + Невозможно проголосовать за сегмент: Статус: %d %s + Нет сегментов для голосования + Голосование за сегмент… + Проголосовано успешно + Голосовать за + diff --git a/src/main/resources/youtube/translations/sk-rSK/strings.xml b/src/main/resources/youtube/translations/sk-rSK/strings.xml new file mode 100644 index 000000000..0ed2284a9 --- /dev/null +++ b/src/main/resources/youtube/translations/sk-rSK/strings.xml @@ -0,0 +1,71 @@ + + + O aplikácií + Táto aplikácia používá API poskytované SponsorBlock-om + Pre viac informácií a možností stiahnutia aj pre iné platformy ťuknite tu: sponsor.ajay.app + Integráciu vytvoril JakubWeg + Zapnúť zjednodušenie ovládania pre video prehrávač? + Vaše ovládiacie prvky sú upravené, pretože je zapnutá služba zjednodušia. + Adresa URL API bola zmenená + Zadaná adresa URL API je neplatná + Adresa URL API bola resetovaná + Chcete zmeniť farby? + "Teraz môžete zmeniť farbu kategórie kliknutím nad ňu." + Farba bola zmenená + Neplatný hexadecimálny kód + Farba bola resetovaná + Čo robiť s rôznymi segmentami + Povoliť SponsorBlock + SponsorBlock je crowdsourcingový systém na preskakovanie otravných častí vo videách Youtubu + Povoliť pridanie nového segmentu + Zapnutím povolíte experimentálne pridávanie segmentov (vzniknú problémy s viditeľnosťou tlačidiel) + Povoliť hlasovanie + Pre povolenie hlasovania zapnite túto možnosť. + Všeobecné + Úprava nového kroku segmentu + Počet milisekúnd, ktoré môžete posunúť, keď používate tlačidlá pre nastavenie času pri pridávaní nového segmentu + Zmeniť adresu URL API + "Adresa, ktorú SponsorBlock používa na uskutočňovanie hovorov na server. <b>Nemeňte ju, ak neviete, čo robíte.</b>" + Minimálna dĺžka segmentu + Segmenty kratšie, ako nastavená hodnota (v sekundách) nebudú preskočené ani zobrazené v prehrávači + Preskočiť počet sledovaní + Toto umožňuje systému SponsorBlock vedieť, koľko času ľudia ušetrili. Rozšírenie odošle správu serveru zakaždým, keď segment preskočíte + Zobraziť informačný text pri automatickom preskočení segmentu + Klepnutím zobrazíte príklad informačného textu + Tento čas sa zobrazí v zátvorkách vedľa aktuálneho času. Zobrazuje sa celkové trvanie videa po odpočítaní všetkých segmentov. + Nastavenie MicroG + minúty + Vyberte kategóriu segmentu + "Segment trvá od %02d:%02d do %02d:%02d (%d minút %02d sekúnd) +Je pripravený na odoslanie?" + Sú časy správne? + "Túto kategóriu ste zakázali v nastaveniach, pre odoslanie ju povoľte" + Chcete upraviť časovanie pre začiatok alebo koniec segmentu? + Zadaný neplatný čas + Hotovo + Ručne upravte časovanie segmentu + koniec + Najprv označte dve miesta na časovej lište + Nastaviť %02d:%02d:%04d ako začiatok alebo koniec nového segmentu? + teraz + Čas, kedy segment končí + Koniec segmentu nastavený + Čas, kedy segment začína + Začiatok segmentu nastavený + Nový SponsorBlock segment + Resetovať + Nastavenia reklám + Karty albumov sú zobrazené z výsledkov vyhľadávania + Karty albumov sú skryté z výsledkov vyhľadávania + Panely s najnovšími správamy sú zobrazené + Panely s najnovšími správamy sú skryté + Skryť pravidlá komunity + Prieskumy kanálov sú skryté + Skryť prieskumy kanálov + Najnovšie príspevky sú zobrazené + Najnovšie príspevky sú skryté + Skryť najnovšie príspevky + Lekárske panely sú zobrazené + Lekárske panely sú skryté + Skryť lekárske panely + diff --git a/src/main/resources/youtube/translations/tr-rTR/strings.xml b/src/main/resources/youtube/translations/tr-rTR/strings.xml new file mode 100644 index 000000000..c4d5ddb60 --- /dev/null +++ b/src/main/resources/youtube/translations/tr-rTR/strings.xml @@ -0,0 +1,616 @@ + + + Hakkında + Bu uygulama SponsorBlock API\'si kullanır + Daha fazla bilgi edinmek ve diğer platformlarda kullanmak için şu adrese dokunun: sponsor.ajay.app + Entegrasyonu yapan: JakubWeg + Video oynatıcı için erişilebilirlik kontrollerini açın? + Bir erişilebilirlik hizmeti açık olduğu için kontrolleriniz değiştirildi. + API URL\'si değiştirildi + Girilen API URL\'si geçersiz + API URL\'si sıfırlandı + API Kaynak URL\'si değiştirildi + Girilen API URL\'si geçersiz + API Kaynak URL\'si sıfırlandı + Renk değiştirmeyi mi arıyorsunuz? + "Artık bir kategorinin rengini yukarıdan değiştirebilirsiniz." + Renk değiştirildi + Renk kodu geçersiz + Renk sıfırlandı + Bu kısımlar ne anlama geliyor + SponsorBlock\'u etkinleştir + SponsorBlock, YouTube videolarındaki sıkıcı kısımları atlamaya yarayan kitle kaynaklı bir sistemdir + SponsorBlock\'u etkinleştir + SponsorBlock API sunucusu kapatıldığında, alternatif API sunucusunu varsayılan API sunucusuna geçirin + Yeni kısım eklemeye izin ver + Kısım eklemek için bu deneysel ayarı kullanın (bazı durumlarda düğmeler görünmeyebilir) + Oylamayı etkinleştir + Etkinleştirerek oylama sistemini kullanabilirsin. + Genel + Yeni kısım adımının ayarlanması + Yeni bir kısmın zamanlamasını düzenlerken düğmeye dokunduğunuzda kaç milisaniye hareket edileceğini buradan ayarlayabilirsiniz + API URL\'sini Değiştir + "SponsorBlock'un sunucuya çağrı yapmak için kullandığı adres. <b>Ne yaptığınızı bilmiyorsanız bunu değiştirmeyin.</b>" + API kaynak URL\'sini değiştirin + "SponsorBlock'un sunucuya çağrı yapmak için kullandığı adres. <b>Ne yaptığınızı bilmiyorsanız bunu değiştirmeyin.</b>" + En az bölüm süresi + Ayarlanan değerden (saniye olarak) daha kısa kısımlar atlanmayacak veya oynatıcıda gösterilmeyecektir + Kaç kere atlandığını say + Bu seçenek sayesinde SponsorBlock liderlik tablosu sistemi, kaç kişinin ne kadar zamanının kurtarıldığını takip edebilir. Video izlerken atladığınız her bir kısım için bu eklenti sunucuya süreyi bildirir + Bir kısım otomatikman atlanırken uyarı ver + Örnek uyarı almak için dokunun + Kısımlar olmadan süreyi göster + Bu süre, videodaki mevcut zamanın yanına yay ayraç (parantez) içinde gösterilir. Videodaki kısımlar kesildikten sonra kalan zamanı gösterir. + Benzersiz kullanıcı kimliğiniz + Bu gizli tutulmalıdır. Bu bir şifre gibidir ve kimseyle paylaşılmamalıdır. Birisi buna sahipse, sizi taklit edebilir + Lütfen MicroG yükleyin + MicroG bulunamadı + Bildirim ayarları + "1. Bildirimler için Google cihaz kaydı ve Bulut Mesajlaşma etkinleştirilmelidir. + 2. ReVanced Extended, Bulut Mesajlaşma altında kayıtlı olarak gösterilmelidir. + 3. Bulut Mesajlaşma'daki Mevcut Durum Bağlı olmalıdır." + MicroG ayarları + dakika + Kategori seçin + "Bu kısmın başlangıcı %02d.%02d, bitişi %02d.%02d, süresi %d dakika %02d saniye. +Gönderilmeye hazır mı?" + Zaman aralığı doğru mu? + "Bu kategoriyi ayarlarda deve dışı bıraktınız, göndermek için etkinleştirmeniz gerekiyor" + Bu kısmın başlangıcını mı, bitişini mi düzenlemek istiyorsunuz? + Girilen süre geçersiz + Bitti + Kısmın süresini elle düzenleyin + bitiş + Öncelikle zaman çizgisinde iki konum işaretleyin + başlangıç + %02d:%02d:%04d bu kısmın başlangıcı mı, bitişi mi olarak ayarlansın? + şimdi + Kısmın bitişi + Kısmın bitişi ayarlandı + Kısmın başlangıcı + Kısmın başlangıcı ayarlandı + Yeni SponsorBlock kısmı + Sıfırla + Reklamla ilgili ayarlar + Reklam ayarları + Gizlenmiyor + Gizleniyor + Albüm kartlarını gizle + Son dakika haber paneli gizlenmiyor + Gizleniyor + Son dakika panelini gizle + Gizlenmiyor + Gizlendi + Butonlu reklamları gizle + Gizlenmiyor + Gizleniyor + Kanal yönergelerini gizle + Gizlenmiyor + Gizleniyor + Bölüm fragmanı seçeneği + Gizlenmiyor + Gizleniyor + Topluluk kurallarını gizle + Gizlenmiyor + Gizleniyor + Topluluk gönderilerini gizle + Gizlenmiyor + Gizleniyor + Kompakt afiş kaldırma + Bileşenleri virgülle ayrılmış adlarına göre filtreleyin + Özel filtre + Gizlenmiyor + Gizleniyor + Acil durum kutusunun kaldırılması + Gizlenmiyor + Gizleniyor + Genel reklamları gizle + Gizlenmiyor + Gizleniyor + Görüntü rafını gizle + Gizlenmiyor + Gizleniyor + Bilgi panelini gizle + Gizlenmiyor + Gizleniyor + Anketleri gizle + Gizlenmiyor + Gizleniyor + Son gönderileri gizle + Gizlenmiyor + Gizleniyor + Tıbbi paneli gizle + Gizlenmiyor + Gizleniyor + Ürünler kısmını gizle + Gizlenmiyor + Gizleniyor + Film rafını kaldır + Gizlenmiyor + Gizleniyor + Resmi kartları gizle + Gizlenmiyor + Gizleniyor + Ücretli içeriği gizle + Gizlenmiyor + Gizleniyor + Kendinden sponsorlu kartlar + Gizlenmiyor + Gizleniyor + Gri ayırıcıları gizle + Gizlenmiyor + Gizleniyor + Önerileri gizle + Gizlenmiyor + Gizleniyor + Zamanlı tepkileri gizle + Kullanıcı filtresi devre dışı + Kullanıcı filtresi etkinleştirildi + Kullanıcı filtresini etkinleştir + Gizlenmiyor + Gizleniyor + \"Ürünler afişini görüntüle\" seçeneğini gizle + Gizlenmiyor + Gizleniyor + Web arama sonuçları + Oynatıcının arabelleğe almaya çalışacağı maksimum medya süresi + Maksimum arabellek boyutu + Videoyu ileri veya geri sarmak gibi eylemler sırasında videonun yürütülmesi için arabelleğe alınacak medya süresi (milisaniye) + + Varsayılan: 2500 + Geri çalma arabelleği boyutu + Yeniden arabelleğe alma işleminden sonra oynatmanın devam etmesi için arabelleğe alınması gereken medyanın süresi + Yeniden arabelleğe alma boyutu + Video arabelleği boyutu ile ilgili ayarlar + Arabellek ayarları + Hücresel Ağda tercih edilen video çözünürlüğünü seçin + Tercih edilen video kalitesi (Hücresel) + Wi-Fi Ağında tercih edilen video çözünürlüğünü seçin + Tercih edilen video kalitesi (Wi-Fi) + Varsayılan video hızını seç + Varsayılan video hızı + kurulmamış. Lütfen önce indiriniz. + "NewPipe veya PowerTube gibi bir indirme uygulaması paket adı" + İndirici paket adı + Varsayılan indirici ile ilgili ayarlar + İndirici ayarları + Gizlenmiyor + Gizleniyor + Bitiş ekranı arayüzü + Gizlenmiyor + Gizleniyor + Film şeridi yerleşimini gizle + Dokunsal geri bildirim temizleme etkinleştirildi + Dokunsal geri bildirim temizleme devre dışı + Dokunsal geri bildirimi temizlemeyi devre dışı bırak + Dokunsal geri bildirim arama etkin + Dokunsal geri bildirim arama devre dışı + Dokunsal geri bildirim arama + Bölümler arasında geçiş yaparken titreşimli geri bildirim etkinleştirildi + Bölümler arasında geçiş yaparken titreşimli geri bildirim kapalı + Bölümler arasında geçiş yaparken titreşimli geri bildirim + Uzun basışta dokunsal geri bildirimi devre dışı bırakın + Titreşimli geribildirimi kapat + Dokunsal yakınlaştırma geri bildirimi etkinleştirildi + Dokunsal yakınlaştırma geri bildirimi devre dışı + Dokunsal yakınlaştırma geri bildirimi + Zaman Damgası panoya kopyalandı + Kapalı + Açık + Otomatik tekrarlama + Oynatıcı kontrolleri göründüğünde kaydırma hareketlerini devre dışı bırakın + Oyuncu kontrollerinin görünüp görünmemesine bakılmaksızın her zaman kaydırma hareketlerini etkinleştirin + Her zaman kaydırma hareketini etkinleştir + Kapalı + Açık + Özel video hızını etkinleştir + Harici tarayıcı devre dışı + Harici tarayıcı etkin + Harici tarayıcı + Yatay HDR videolardaki parlaklık cihazınızın parlaklık seviyesinde kalacak + Yatay HDR videolardaki video parlaklığı en yükseğe ayarlandı + HDR En yüksek parlaklık + Arka planda mini oynatıcı devre dışı + Arka planda mini oynatıcı etkin + Küçültülmüş oynatmayı etkinleştir + YouTube Düzeni, Google Hesabı durumunuzu takip edecek + Eski düzeni etkinleştirmeye zorlamak için YouTube görünümü değiştirin + Eski düzeni Etkinleştir + Video kalitesi ayarları için varsayılan stil kullanılıyor + Video kalitesi ayarları için eski stil kullanılıyor + Eski stilde kalite arayüzünü etkinleştir + URL (youtube.com/redirect), video açıklamalarındaki linkleri açarken kullanılır + Video açıklamalarındaki bağlantıları açarken URL yönlendirmelerini (youtube.com/redirect) atlayın + Bağlantıları direkt açmayı etkinleştir + Basılı-tut-kaydır devre dışı + Basılı-tut-kaydır etkin + Basılı tut ve kaydır + Bazı telefon düzenlerini kullanmak için dpi\'yi kandırır + Telefon düzenini Etkinleştir + Zaman çubuğuna (video ilerleme çubuğu) dokunma devre dışı + Video kalitesini değiştirseniz bile varsayılan değer olarak kaydetmez + Video kalitesini her değiştirdiğinizde varsayılan değer olarak kaydeder + Video kalitesini kaydetmeyi etkinleştir + Zaman çubuğuna (video ilerleme çubuğu) dokunma etkin + Zaman çubuğuna dokunma + Parlaklık kaydırılarak 0 olarak ayarlansa bile otomatik parlaklık etkinleştirilmez + Kaydırarak parlaklık 0\'a ulaştığında, otomatik parlaklık etkinleştirilir + Oto parlaklık için kaydırma kontrolleri + Kapalı + Açık + Parlaklık için kaydırma kontrolleri + Bas ve kaydır dokunsal geri bildirim devre dışı bırakıldı + Bas ve kaydır dokunsal geri bildirim etkin + Bas ve kaydır dokunsal geri bildirimi etkinleştir + Kapalı + Açık + Ses hareketlerini etkinleştir + Kapalı + Açık + Tablet mini oynatıcısını etkinleştir + Bazı tablet düzenlerini kullanmak için dpi\'yi kandırır + Tablet düzenini Etkinleştir + Kapalı + Açık + Geniş arama çubuğunu etkinleştir + Deneysel parametreler + Report issues or leave suggestions here + ReVanced Extended sorun merkezi + ReVanced Gelişmiş ayarlar + Gelişmiş ayarlar + Genişletilmiş Ayarlar + Video oynatma arabelleği sorunlarını düzeltme kapalı + Video oynatma arabelleği sorunlarını düzeltme açık + Video oynatma arabelleği sorunlarını düzelt + Altyazılı bir video oynatılırken altyazılar etkinleştirildi + "Altyazılı bir video oynatılırken altyazılar etkinleştirilmedi" + Otomatik altyazıları gizle + Otomatik oynatıcı açılır panelleri gösterilir + Otomatik oynatıcı açılır panelleri gizli + Otomatik oynatıcı açılır panelleri + Açık + Kapalı + \"Otomatik oynat\" butonunu gizle + Buton kapsayıcısının bileşenini gizler + Buton kapsayıcısını gizle + Klip butonu gösterilir + Klip butonu saklı + Klip butonunu gizle + Short oluştur butonu gösterilir + Short oluştur butonu gizlenir + Short oluştur butonunu gizle + Gizlenmiyor + Gizleniyor + Beğenme butonunu gizle + İndirme butonu gösterilir + İndirme butonu gizlenir + İndir Butonunu Gizle + Gizlenmiyor + Gizleniyor + Beğen butonunu gizle + Gizlenmiyor + Gizleniyor + Canlı sohbet butonunu gizle + Gizlenmiyor + Gizleniyor + Oynatma Listesi Butonunu Gizle + Rapor düğmesi görünür durumda + Rapor düğmesi gizli durumda + Rapor butonunu gizle + Paylaş düğmesi görünür durumda + Paylaş düğmesi gizli durumda + Paylaş butonunu gizle + Teşekkürler düğmesi görünür durumda + Teşekkürler düğmesi gizli durumda + Teşekkürler butonunu gizle + Altyazılar butonu görünür durumda + Altyazılar butonu gizli durumda + Altyazılar butonunu gizle + \"Yayınla\" butonu görünür durumda + \"Yayınla\" butonu gizli durumda + \"Yayınla\" butonunu gizle + Açık + Kapalı + Kanal filigranını gizle + Yorumlar bölümünü veya bileşenini gizler + Yorumlar bileşeni + Gizlenmiyor + Gizleniyor + Yorumlar bölümünü gizle + Açık + Kapalı + Oluştur butonunu gizle + Açık + Kapalı + Kitle fonlaması kutusu + Gizlenmiyor + Gizleniyor + Email adresini sakla + Gizlenmiyor + Gizleniyor + Bitiş ekranı arayüzü + Gizlenmiyor + Gizleniyor + Tam ekran buton kapsayıcısı + Açık + Kapalı + Hakkında Kartlarını Gizle + \"Ambiyans modu\" menüsü gizleniyor + \"Ambiyans modu\" menüsü gizli + \"Ambiyans modu\" menüsü + \"Ses parçası\" menüsü gösterilir + \"Ses parçası\" menüsü gizli + \"Ses parçası\" menüsü + \"Altyazılar\" menüsü gösterilir + \"Altyazılar\" menüsü gizli + \"Altyazılar\" menüsü + Yardım & geri bildirim menüsü gösterilir + Yardım & geri bildirim menüsü gizlendi + Yardım & geri bildirim menüsünü gizle + Dinleme kontrolleri menüsü gösterilir + Dinleme kontrolleri menüsü gizli + Dinleme kontrolleri menüsü + \"YouTube Music ile dinle\" menüsü gösterilir + \"YouTube Music ile dinle\" menüsü gizli + \"YouTube Music ile dinle\" menüsü + \"Döngü\" menüsü gösterilir + \"Döngü\" menüsü gizli + \"Döngü\" menüsü + \"Daha fazla bilgi\" menüsü gösterilir + \"Daha fazla bilgi\" menüsü gizli + Daha Fazla Bilgi Menüsünü Gizle + Rapor Menüsü Gösteriliyor + Raport Menüsü Saklı + Rapor Menüsünü Sakla + \"Meraklısı için istatikler\" menüsü gösteriliyor + \"Meraklısı için istatikler\" menüsü gizli + \"Meraklısı için istatikler\" menüsü + \"VR modunda izle\" menüsü gösteriliyor + \"VR modunda izle\" menüsü gizli + \"VR modunda izle\" menüsü + Açık + Kapalı + Mix Oynatma Listesini sakla + Oynatıcı bindirme filtresi gösteriliyor + Oynatıcı bindirme filtresi gizli + Oynatıcı arayüzü filtresini gizle + Önizleme yorumu gösterilir + Önizleme yorumu gizli + Önizleme yorumları gizle + Shorts düğmesi görünür durumda + Shorts düğmesi gizli durumda + Shorts düğmesini gizle + Shorts bileşenini veya Shorts oynatıcı bileşenini gizler + Shorts bileşeni + Gizlenmiyor + Gizleniyor + Shorts oynatıcı yorumlar butonu + Shorts oynatıcı bileşeni + Gizlenmiyor + Gizleniyor + Shorts oynatıcı remiks seçeneği + Gizlenmiyor + Gizleniyor + Shorts oynatıcı abonelikler butonu + Gizlenmiyor + Gizleniyor + Shorts oynatıcı teşekkürler butonu + Gizlenmiyor + Gizleniyor + Kısa videoları gizle + Kapalı + Açık + Shorts videolarını açılışta oynat + Gizlenmiyor + Gizleniyor + Hikayeleri gizle + Gizlenmiyor + Gizleniyor + Tam ekrandaki \"Diğer videolar\" + Açık + Kapalı + Zaman ve arama çubuğu + Alt oynatıcı düzeni ayarları + Açılır menü düzeni ayarları + Tam ekran arayüz ayarları + Genel Arayüz ayarları + Oynatıcı arayüz ayarları + Arama çubuğu düzeni ayarları + Düzenle ilgili ayarlar + Arayüz ayarları + Çeşitli ilgili ayarlar + Diğer Seçenekler + Diğerleri + Kapalı + Açık + Otomatik tekrarlama butonu + Gizleniyor + Gizlenmiyor + Linki kopyala butonu + Gizlendi + Gizlenmiyor + Bağlantıyı kopyala (Zaman damgalı) butonu + İndirme butonu gizlenir + İndirme butonu gösterilir + İndirme düğmesini göster + Bindirme butonu ile ilgili ayarlar + Bindirme butonu ayarları + Beyaz Liste butonu gizli + Beyaz Liste butonu gösteriliyor + Beyaz Liste düğmesini göster + Geçerli Başlık: Varsayılan Başlık + Geçerli Başlık: Premium Başlık + Premium Başlık + Uygulanmış Yamalar Hakkında Bilgi + Yama Bilgileri + Oynatıcı ayarları açılır panelinin bileşenini gizler + Oynatıcı ayarları açılır panelinin bileşeni + "Bu henüz deneysel bir özellik olduğundan, bilinmeyen başka sorunlar olabilir. Yine de devam etmek istediğinizden emin misiniz?" + "Eski düzeni yüklemek için YouTube istemci sürümünü v17.28.35 olarak kandırır Uygulama ayarlarında, YouTube sürümü v17.28.35 olarak işaretlenmiş olabilir" + "Bazı düzenleri telefon düzenlerine çevirmek için dpi'yi kandırır. + + Bu ayarı etkinleştirirseniz, aşağıdaki özellikler kullanılabilir: + - Topluluk Gönderileri +- Mix oynatma listesini gizle" + "Bazı bölgelerde video oynatma arabelleği sorunlarını düzeltin. + +Bu ayarı etkinleştirirseniz, aşağıdaki sorun oluşabilir: +- Oynatma listesindeki bir videoyu oynatırken sorun çözülmeyebilir" + "Bazı düzenleri tablet düzenlerine dönüştürmek için dpi'yi kandırır. + +Bu ayarı etkinleştirirseniz aşağıdaki özellikler kullanılamaz: +- Ortam modu +- Topluluk Gönderileri" + Beğenmeme verileri True RYD Worker API tarafından sağlanır. Daha fazlasını öğrenmek için buraya dokunun. + true-ryd.cane.workers.dev + Alternatif API kapalı + Yansıma API\'si aktif + Kaynak API\'sini Etkinleştir + "True RYD Worker API, YouTube API Uç Noktasında gösterilen beğenmeme sayısını kullanır. + +Bu seçeneği yalnızca varsayılan RYD API'sini kullanırken sorun yaşayanlar için etkinleştirin. + + Devam etmek ister misin?" + Gerçek RYD Çalışanı + Beğenmeme verileri True RYD Worker API tarafından sağlanır. Daha fazlasını öğrenmek için buraya dokunun. + ReturnYouTubeDislike.com + Beğenmemeler sayı olarak gösterilir + Beğenmemeler yüzde olarak gösterilir + Beğenmemeleri yüzde olarak gösterir + Beğenmemeler gösterilmiyor + Açık + YouTube Dislike ayarları + Beğenmeme sayısı mevcut değil (istemci API sınırına ulaşıldı) + ReturnYouTubeDislike yeni kullanıcıyı onaylayamadı + ReturnYouTubeDislike oyu onaylayamadı + Beğenmemeler geçici olarak kullanılamıyor (API zaman aşımına uğradı) + ReturnYouTubeDislike yeni kullanıcı kaydını onaylayamadı + ReturnYouTubeDislike oyu göndermeyi onaylayamadı + Return YouTube Dislike ayarları + Return YouTube Dislike + ReVanced Ayarları + Kaydırma Tabanlı Kontroller Ayarları + Kaydırma Kontrolleri Ayarları + Kaydırma işleminin gerçekleşmesi için eşik miktarı + Kaydırma büyüklük eşiği + Kaydırma arka planının şeffaflık değeri + Kaydırma arka plan şeffaflığı + Kaydırma animasyonu için metin boyutu + Kaydırma metin boyutu + Kaplamanın görünür olduğu milisaniye miktarı + Kaydırma zaman aşımı + araç kullanıldı + Gizlenmiyor + Gizlendi + Video reklamlarını gizle + Kalite ayarlanamadı + İnternet bağlantısı yok + Varsayılan mobil veri kalitesi şu şekilde değiştiriliyor: + Varsayılan mobil veri kalitesi değiştirilemedi + Varsayılan Wi-Fi kalitesi şu şekilde değiştiriliyor: + Varsayılan Wi-Fi kalitesi değiştirilemedi + Videoyla ilgili ayarlar + Video ayarları + Kanal %s, %s beyaz listeye eklenemedi + Kanal %s, %s beyaz listeye eklendi + Video reklamları + Reklamlar + Kanal Adı + Beyaz listeye alınmış kanal yok + BeyazListeye eklenmedi + BeyazListeye Eklendi + Kanal beyaz listesi + Kanal detayları alınamadı, %d kodu alındı + Kanal beyaz listesi ayarlarını uygulamak için yeniden başlatın + Kanal %s, %s beyaz listesinden kaldırılamadı + Kanal %s, %s beyaz listesinden kaldırıldı + Beyaz listeye alınan kanalları kontrol et veya kaldır + Beyaz liste ayarları + Video Hızı + Hız + SponsorBlock + SB + Sponsorblock sunucusu yanıt vermiyor! + Zaten okundu + "Herhangi bir kısmı göndermeden önce SponsorBlock kurallarını okumanız tavsiye edilir" + Göster bana + Yönergeler var + Yönergeler, bir kısım göndermeyle ilgili ipuçları içerir + Yönergeleri görüntüle + SponsorBlock ayarları + SponsorBlock ilgili ayarları + Geçiş Başarılı. Video\'yu yeniden yükle + Alternatif API sunucusu ana API sunucusuna geçiriliyor.. + Kapanış Sahneleri/Jenerik + Videoda emeği geçenlerin veya video sonunda çıkan kartların gösterildiği kısımlar. Bu kısımlarda konuşma yoktur + Konuyla Alakasız/Şaka + Sadece videoyu doldurmak ya da mizah için eklenmiş, videonun ana içeriğini anlamak için gerekli olmayan alakasız sahneler. Bu, içerik veya arka plan detayları hakkında bilgi veren kısımları içermemelidir + Aralık/Giriş Animasyonu + Asıl içeriğin bulunmadığı bir aralık. Duraksama, sabit ekran, tekrarlayan bir animasyon olabilir + Müzik: Müzik Olmayan Bölüm + Bu ayar sadece müzik klipleri içindir. Buna kliplerin başlarında ve sonlarında şarkı bulunmayan kısımlar dahildir + Ön İzleme/Özet + "Önceki bölümlerin bir özeti veya geçerli videonun içeriğine yönelik bir ön izleme. Bu özellik birleştirilmiş klipler içindir, konuşarak anlatılan özetleri kapsamaz." + Karşılıksız/Kendi Reklamı + \"Sponsor\" seçeneğinden farkı para karşılığı olmaması veya kendi reklamını yapmasıdır. Buna kendi markalı ürünlerini satmak, bağış toplamak ve videoda işbirliği yaptığı kimselerden bahsetmek dahildir + Sponsor + Ücretli tanıtım, ücretli yönlendirmeler ve doğrudan reklamlar + Etkileşim Anımsatıcısı (Abonelik) + Video içerisinde \"beğenin, yorum yapın, takip edin\" şeklindeki kısımlar + Ayarlar dışarı aktarılamadı + Ayarları içe - dışa aktar + Tüm ayarlarınız, JSON biçiminde ve masaüstü eklentisiyle uyumlu şekilde saklanır. Bu sizin kullanıcı kimliğinizi de içerir, bu yüzden bunu paylaşırken iki kez düşünün. + Ayarlar içeri aktarılamadı + Ayarların içe aktarılması tamamlandı + Otomatik atla + Bir kez otomatik atla + "Hiçbir şey yapma" + Atlamak için buton göster + Kısımları atla + Kapanış ekranı atlandı + Alakasız konu atlandı + Giriş ekranı atlandı + Müzik olmayan kısım atlandı + Önizleme atlandı + Sponsor kısmı atlandı + Kendi reklamı atlandı + Sponsor atlandı + Etkileşim anımsatıcısı atlandı + Gönderilmemiş kısım atlandı + İstatistikler + Yükleniyor.. + "İnsanları <b>%s</b> kısımdan kurtardın." + "Bu da toplamda <b>%s</b> süre demek. Liderlik tablosunu görmek için tıkla" + SponsorBlock devre dışı + "<b>%s</b> kısmı atladın." + "Bu da <b>%s</b> demek." + Gönderdiklerin: <b>%s</b> + Kullanıcı adın: <b>%s</b> + Kullanıcı adını değiştirmek için buraya dokun + Kullanıcı adı değiştirilemiyor: Durum: %d %s + Kullanıcı adı başarıyla değiştirildi + "Kısım gönderilemedi. +Aynısı mevcut" + "Kısım gönderilemiyor. + +%s" + "Kısım gönderilemedi. +Oylama Sınırlandı (Aynı kullanıcıdan veya IP'den çok fazla düzenleme)" + Kısım gönderilemiyor: %s + Kısımlar gönderilemedi. Durum: %d %s + Kısım gönderiliyor… + Düzenlenen kısım gönderimi tamamlandı + Atlamak için dokunun + Kategoriyi değiştir + Olumsuz oy + "Kısım için oy kullanılamıyor. + +%s" + "Oylama başarısız. +Sınır Aşıldı (Aynı kullanıcıdan veya IP'den çok fazla oy iletildi)" + Kısım oylanamadı. Durum: %d %s + Oylanabilecek bir kısım yok + Oylanıyor… + Oylama başarılı + Olumlu Oy Ver + diff --git a/src/main/resources/youtube/translations/uk-rUA/strings.xml b/src/main/resources/youtube/translations/uk-rUA/strings.xml new file mode 100644 index 000000000..25eaa626e --- /dev/null +++ b/src/main/resources/youtube/translations/uk-rUA/strings.xml @@ -0,0 +1,242 @@ + + + Про нас + Цей додаток використовує API з SponsorBlock + Натисніть, щоб дізнатися більше, і побачити завантаження для інших платформ на: sponsor.ajay.app + Автор інтеграції - JakubWeg, написав - oSumAtrIX + Увімкнути спеціальні можливості для відеоплеєра? + Керування змінено, оскільки служба спеціальних можливостей увімкнена. + API URL змінено + Вказана URL-адреса API недійсна + Скинути URL-адресу для API + API MIRROR URL змінена + Вказаний API MIRROR URL-адреса недійсна + Скинути URL-адресу для API MIRROR + Хочете змінити колірну схему? + "Ви можете змінити кольори категорій натиснувши тут." + Колір змінено + Неправильний hex код + Скинути колір + Що робити з різними сегментами + Увімкнути SponsorBlock + SponsorBlock - це краудсорсингова система для пропуску дратівливих частин у відео на YouTube + Увімкнути SponsorBlock + Коли API-сервер SponsorBlock вимкнено, перемкніть дзеркальний API-сервер на стандартний API-сервер + Увімкнути додавання нового сегмента + Увімкніть це для активації експериментального додавання сегмента (наявні проблеми з видимістю кнопки) + Увімкнути голосування + Увімкніть для використовування функції голосування. + Загальні + Коректування нового кроку сегменту + Кількість мілісекунд, на які буде переміщено час при використанні кнопок перемотки часу при додаванні нового сегменту + Змінити URL-адресу для API + "Адреса SponsorBlock сервера. <b>Змінюйте, тільки якщо розумієте, що робите.</b>" + Змінити URL-адресу для API Mirror + "Адреса дзеркального сервера для перемикання, коли сервер SponsorBlock вимкнено. <b>Змінюйте, тільки якщо розумієте, що робите.</b>" + Мінімальна тривалість сегменту + Сегменти коротше цього значення (у секундах) не будуть пропускатися і не будуть показуватися у плеєрі + Відстеження кількості пропусків + Це дозволяє системі рейтингу SponsorBlock дізнатися, скільки часу зберегли люди. Розширення надсилає повідомлення на сервер кожного разу, коли ви пропускаєте сегмент + Показувати спливаюче сповіщення якщо сегмент пропущено автоматично + Натисніть, щоб побачити приклад спливаючого сповіщення + Показувати час без сегментів + Цей час з\'являється в дужках поруч з поточним часом, та показує загальну тривалість відео без сегментів. + Ваш унікальний ID користувача + Це потрібно тримати в таємниці. Це як пароль, не варто ним ні з ким ділитися. Якщо хтось матиме це - зможе видати себе за вас + Будь ласка, встановіть MicroG + MicroG не знайдено + Налаштування сповіщень + "1. Реєстрація пристроїв Google і Google Cloud Messaging повинні бути увімкненими для сповіщень.\n2. Vanced повинен бути показаний зареєстрованим під GCM.\n3. Поточний стан у GCM повинен не бути Від'єднано.\n4. GCM -> Розширені (три точки справа згори) і змініть інтервал очікування Wi-Fi назад і вперед раз для з'єднання.\n💙💛" + Налаштування MicroG + хв. + Виберіть категорію сегмента + "Сегмент триває від %02d:%02d до %02d:%02d (%d хвилин(-и) %02d секунд(-и))\n Відправляємо?" + Час початку і кінця сегмента правильні? + "Ви вимкнули цю категорію в налаштуваннях. Увімкніть її, щоб передати сегмент" + Ви хочете змінити час початку або кінця сегмента? + Вказано неправильний час + Виконано + Редагування часу сегмента вручну + кінець + Спочатку позначте дві позиції на панелі часу + розпочати + Встановити %02d:%02d:%04d як початок або кінець нового сегмента? + зараз + Час закінчення сегмента + Кінець задання сегмента + Час початку сегмента + Початок задання сегмента + Новий SponsorBlock сегмент + Скинути + Вилучення карти альбомів у результатах пошуку вимкнено + Вилучення карти альбомів у результатах пошуку увімкнемо + Вилучення картки альбома + Вилучення важливих новин вимкнено + Вилучення важливих новин увімкнено + Вилучення важливих новин + Вилучення рекомендацій по каналу вимкнено + Вилучення рекомендацій по каналу увімкнено + Вилучення рекомендації по каналу + Вилучення правил спільноти вимкнено + Вилучення правил спільноти увімкнено + Вилучення правил спільноти + Вилучення публікацій у спільноті вимкнено + Вилучення публікацій у спільноті увімкнено + Вилучення публікації в спільноті + Вилучення компактного банера вимкнено + Вилучення компактного банера увімкнено + Вилучення компактного банера + Вилучення \"аварійної скриньки\" вимкнено + Вилучення \"аварійної скриньки\" увімкнено + Вилучення аварійної скриньки + Вилучення оголошень на головній сторінці вимкнено + Вилучення оголошень на головній сторінці увімкнено + Вилучення оголошень на головній сторінці + Вилучення зображень (із пошуку на YouTube) вимкнено + Вилучення зображень (із пошуку на YouTube) увімкнено + Вилучення зображень + Вилучення інформаційної панелі вимкнено + Вилучення інформаційної панелі увімкнено + Вилучення Інформаційної панелі + Вилучення опитувань вимкнено + Вилучення опитувань увімкнено + Вилучення опитувань + Вилучення останніх дописів вимкнено + Вилучення останніх дописів увімкнено + Вилучення останніх дописів + Вилучення панелі про медицину вимкнено + Вилучення панелі про медицину увімкнено + Вилучення панелі про медицину + Вилучення товарних банерів вимкнено + Вилучення товарних банерів увімкнено + Вилучення товарних банерів + Вилучення компактного фільму вимкнено + Вилучення компактного фільму увімкнено + Вилучення компактних фільмів + Вилучення офіційних карток у результатах пошуку вимкнено + Вилучення офіційних карток у результатах пошуку увімкнено + Вилучення офіційної картка у результатах пошуку + Вилучення платного контенту вимкнено + Вилучення платного контенту увімкнено + Вилучення платного контенту + Експериментальні опції + Додаткові налаштування ReVanced Extended + Додаткові налаштування розширеного + Розширені налаштування + Вилучення розділу коментарів вимкнено + Вилучення розділу коментарів увімкнено + Розділ коментарів + Електронну пошту вимкнено + Електронну пошту увімкнено + Електронна пошта + Вилучення спойлерів коментарів вимкнено + Вилучення спойлерів коментарів увімкнено + Спойлер коментарів + Смугу для перемотування та час перегляду вимкнено + Смугу для перемотування та час перегляду увімкнено + Смуга та час перегляду + Додаткові налаштування вигляду + Налаштування вигляду + Заголовок:YOUTUBE\n(Натисніть, щоб змінити заголовок) + Заголовок:Premium\n(Натисніть, щоб змінити заголовок) + Premium заголовок на головній сторінці + Ця інтеграція використовує RYD API з https://returnyoutubedislike.com \nНатисніть тут, щоб отримати більше інформації. + Інтеграція Return YouTube Dislike + Використовується RYD API + Налаштування Return YouTube Dislike + Налаштування ReVanced + Мінімальна амплітуда руху, що розпізнається як жест + Поріг величини жесту + Розмір шрифту в оверлеї + Розмір шрифту оверлея + Як довго оверлей відображатиметься після зміни + Тривалість оверлею + Патч збірки: + Не вдалося встановити типові параметри якості відео + Відсутнє підключення до Інтернету + Типові параметри якості відео під час перегляду через мобільну мережу: + Не вдалося задати типові параметри якості відео для мобільної мережі + Типові параметри якості відео при перегляді через Wi-Fi: + Не вдалося задати типові параметри якості відео для Wi-Fi + Додаткові налаштування відео + Налаштування відео + Не вдалося додати канал %s до білого списку %s + Канал %s був доданий до білого списку %s + Реклама + Не вдалося отримати дані про канал, отримано код %d + Не вдалося видалити канал %s із білого списку %s + Канал %s видалено з білого списку %s + SponsorBlock + Вже прочитано + "Перед відправною будь-якого сегмента рекомендується прочитати Sponsor Block інструкції" + Показати + Існують рекомендації + Інструкція містить поради щодо надсилання сегмента + Переглянути інструкцію + Налаштування SponsorBlock + Використовує sponsor.ajay.app API + Кінцева заставка/титри + Титри або час появи кінцевих заставок YouTube. Не для підведення підсумків сказаного у відео. + Жарти без контекста + Сцени додані як жарти і не потрібні для розуміння основного змісту відео. Не для сегментів, що пояснюють контекст чи передісторія. + Пауза/Заставка + Інтервал без фактичного вмісту. Може бути паузою, статичним кадром, повторенням анімації. + Музика: Сегмент без музики + Тільки для використання в музичних кліпах. Включає в себе початкові і кінцеві заставки кліпів. + Попередній перегляд/короткий зміст + "Короткий зміст попередніх епізодів або попередній перегляд того, що буде в даному відео. Призначено для сегментів, змонтованих зі шматків відео, а не для усних переказів." + Самореклама/рекомендація + Схоже на \"Спонсора\", але для безкоштовної реклами і самореклами. Включає себе вставки про мерчендайз, пожертвування або інформацію про тих, разом з ким було зроблено відео. + Спонсор + Рекламні інтеграції, реферальні посилання та реклама напряму. + Нагадування про взаємодію (підписка) + Коли в середині контенту є нагадування поставити лайк, чи підписатися. + Не вдалося експортувати налаштування + Імпорт/Експорт налаштувань + Це вся конфігурація, яка застосовується в настільному розширенні в JSON. Включаючи ваш userID, так що не забудьте користуватися цим розумно. + Не вдалося імпортувати дані + Налаштування було вдало імпортовано + Автоматично пропускати + "Не робити нічого" + Показувати кнопку пропуску + Пропустити сегмент + Пропущено закінченння + Пропущена вставка + Пропущено вступ + Пропущено тишу + Пропущено прев\'ю + Пропущено спонсорський сегмент + Пропущена самореклама + Пропущений спонсор + Пропущено дратівливе нагадування + Пропущений непредставлений сегмент + Статистика + Завантаження.. + "Ви зберегли людей від <b>%s</b> сегментів." + "Це <b>%s</b> їх життя. Натисніть, щоб побачити таблицю лідерів" + SponsorBlock вимкнено + "Ви пропустили <b>%s</b> сегментів." + "Це <b>%s</b>." + Заявки: <b>%s</b> + Ваше ім\'я користувача: <b>%s</b> + Натисніть, щоб змінити ім\'я користувача + Не вдалося змінити ім\'я користувача: Статус: %d %s + Ім\'я користувача успішно змінено + "Неможливо відправити сегмент.\nВже існує" + "Не вдалося надіслати сегмент.\n\n%s" + "Неможливо відправити сегмент.\nЧастота обмежена (занадто багато від одного користувача або IP)" + Не вдається надіслати сегмент: %s + Не вдалося надіслати сегменти: Статус: %d %s + Відправлення сегменту… + Сегмент успішно відправлено + Натисніть, щоб пропустити + Змінити категорію + Голос \"проти\" + "Не вдалося проголосувати за сегмент.\n\n%s" + "Неможливо проголосувати за сегмент.\nШвидкість Обмежена (Занадто багато від одного користувача або IP)" + Не вдалося проголосувати за сегмент: Статус: %d %s + Немає сегментів для голосування + Голосування за сегмент… + Проголосовано + Голос \"за\" + diff --git a/src/main/resources/youtube/translations/vi-rVN/strings.xml b/src/main/resources/youtube/translations/vi-rVN/strings.xml new file mode 100644 index 000000000..0eaf2a47b --- /dev/null +++ b/src/main/resources/youtube/translations/vi-rVN/strings.xml @@ -0,0 +1,617 @@ + + + Thông tin + Ứng dụng này sử dụng API từ SponsorBlock + Nhấn để tìm hiểu thêm và xem tải xuống cho các nền tảng khác tại: sponsor.ajay.app + Tích hợp này được thực hiện bởi JakubWeg + Bật các điều khiển trợ năng cho trình phát video? + Các điều khiển của bạn đã được sửa đổi vì dịch vụ trợ năng đang bật. + URL API đã thay đổi + URL API được cung cấp không hợp lệ + Đặt lại URL API + URL mirror API đã thay đổi + URL mirror API đã cung cấp không hợp lệ + Đặt lại URL mirror API + Bạn đang muốn thay đổi màu sắc? + "Bây giờ bạn có thể thay đổi màu sắc của danh mục bằng cách nhấn vào nó ở trên." + Màu sắc đã được thay đổi + Mã hex không hợp lệ + Đặt lại màu sắc + Làm gì với các phân đoạn khác nhau + Bật SponsorBlock + SponsorBlock là một tích hợp được đóng góp từ cộng đồng để bỏ qua các phân đoạn khó chịu trong video trên YouTube + Bật SponsorBlock Mirror + Khi máy chủ API SponsorBlock bị gỡ xuống, hãy chuyển máy chủ API mirror sang máy chủ API mặc định + Bật Thêm phân đoạn mới + Bật tùy chọn này để kích hoạt tính năng Thêm phân đoạn thử nghiệm (Các nút có thế có vấn đề về khả năng hiển thị) + Bật Bình chọn + Bật tùy chọn này để kích hoạt tính năng Bình chọn. + Chung + Điều chỉnh khoảng cách của phân đoạn mới + Đây là số mili giây bạn có thể di chuyển khi sử dụng các nút điều chỉnh thời gian trong khi thêm phân đoạn mới + Thay đổi URL API + "Địa chỉ SponsorBlock được dùng để thực hiện các kết nối đến máy chủ. <b> Đừng thay đổi địa chỉ này trừ khi bạn biết mình đang làm gì.</b>" + Thay đổi URL mirror API + "Địa chỉ máy chủ mirror để chuyển sang khi máy chủ SponsorBlock bị gỡ xuống. <b>Không thay đổi điều này trừ khi bạn biết mình đang làm gì.</b>" + Thời lượng phân đoạn tối thiểu + Các phân đoạn ngắn hơn giá trị đã đặt (tính bằng giây) sẽ không bị bỏ qua hoặc hiển thị trong trình phát + Theo dõi số lượng phân đoạn đã bỏ qua + Cài đặt này cho phép hệ thống bảng xếp hạng của SponsorBlock biết mọi người đã tiết kiệm được bao nhiêu thời gian. Tiện ích sẽ gửi thông tin đến máy chủ mỗi khi bạn bỏ qua một phân đoạn + Hiển thị một thông báo ngắn khi tự động bỏ qua phân đoạn + Nhấn để xem một ví dụ về thông báo ngắn + Hiển thị thời gian không có phân đoạn + Thời gian này hiển thị trong dấu ngoặc bên cạnh thời gian hiện tại. Nó cho biết tổng độ dài của video trừ đi các phân đoạn. + ID người dùng riêng tư của bạn + Mã ID này nên được giữ riêng tư. Nó giống như mật khẩu và không nên được chia sẻ với bất kỳ ai. Nếu ai đó có nó, họ có thể mạo danh bạn + Vui lòng cài đặt MicroG + MicroG chưa được cài đặt + Nhận thông báo + "1. Cần bật tính năng Đăng ký thiết bị Google và Thông báo đẩy qua đám mây để nhận thông báo. +2. ReVanced Extended cần được hiển thị như một ứng dụng đã đăng ký trong dịch vụ Thông báo đẩy qua đám mây. +3. Trạng thái hiện tại trong dịch vụ Thông báo đẩy qua đám mây phải được hiển thị là \"Đã kết nối...\"." + Cài đặt MicroG + phút + Chọn danh mục phân đoạn + "Phân đoạn kéo dài từ %02d:%02d đến %02d:%02d (%d phút %02d giây). +Bạn đã sẵn sàng để gửi đi chưa?" + Thời gian đã đúng chưa? + "Bạn đã tắt danh mục này trong cài đặt, hãy bật lại để có thể gửi đi" + Bạn có muốn thay đổi thời gian bắt đầu hoặc kết thúc của phân đoạn không? + Thời gian đã đặt không hợp lệ + Hoàn thành + Chỉnh sửa thời gian của phân đoạn theo cách thủ công + kết thúc + Đánh dấu hai vị trí đầu - cuối trên thanh thời gian trước + bắt đầu + Đặt %02d:%02d:%04d là bắt đầu hay kết thúc của một phân đoạn mới? + bây giờ + Thời gian phân đoạn kết thúc lúc + Đặt thời gian kết thúc phân đoạn + Thời gian phân đoạn bắt đầu lúc + Đặt thời gian bắt đầu phân đoạn + Tạo phân đoạn SponsorBlock mới + Đặt lại + Các tùy chọn cài đặt liên quan đến quảng cáo + Quảng cáo + Thẻ Đĩa nhạc được hiển thị trong kết quả tìm kiếm + Thẻ Đĩa nhạc đã ẩn khỏi kết quả tìm kiếm + Ẩn thẻ Đĩa nhạc khỏi kết quả tìm kiếm + Kệ Tin nổi bật được hiển thị + Kệ Tin nổi bật đã ẩn + Ẩn kệ Tin nổi bật + Quảng cáo có nút được hiển thị + Quảng cáo có nút đã ẩn + Ẩn Quảng cáo có nút + Nguyên tắc kênh được hiển thị + Nguyên tắc kênh đã ẩn + Ẩn Nguyên tắc kênh + Giới thiệu phân cảnh bên dưới video được hiển thị + Giới thiệu phân cảnh bên dưới video đã ẩn + Ẩn Giới thiệu phân cảnh bên dưới video + Nguyên tắc cộng đồng được hiển thị + Nguyên tắc cộng đồng đã ẩn + Ẩn Nguyên tắc cộng đồng + Bài đăng trên thẻ Cộng đồng được hiển thị + Bài đăng trên thẻ Cộng đồng đã ẩn + Ẩn Bài đăng trên thẻ Cộng đồng + Biểu ngữ thu gọn được hiển thị + Biểu ngữ thu gọn đã ẩn + Ẩn Biểu ngữ thu gọn + Lọc các thành phần theo tên và được phân tách bằng dấu phẩy + Bộ lọc tùy chỉnh + Hộp khẩn cấp được hiển thị + Hộp khẩn cấp đã ẩn + Ẩn Hộp khẩn cấp + Quảng cáo chung được hiển thị + Quảng cáo chung đã ẩn + Ẩn Quảng cáo chung + Kệ Hình ảnh được hiển thị + Kệ Hình ảnh đã ẩn + Ẩn kệ Hình ảnh + Bảng thông tin được hiển thị + Bảng thông tin đã ẩn + Ẩn Bảng thông tin + Khảo sát được hiển thị + Khảo sát đã ẩn + Ẩn Khảo sát + Bài đăng mới nhất được hiển thị + Bài đăng mới nhất đã ẩn + Ẩn Bài đăng mới nhất + Bảng y tế được hiển thị + Bảng y tế đã ẩn + Ẩn Bảng y tế + Biểu ngữ hàng hoá được hiển thị + Biểu ngữ hàng hoá đã ẩn + Ẩn Biểu ngữ hàng hoá + Kệ Phim ảnh được hiển thị + Kệ Phim ảnh đã ẩn + Ẩn kệ Phim ảnh + Thẻ chính thức được hiển thị trong kết quả tìm kiếm + Thẻ chính thức đã ẩn khỏi kết quả tìm kiếm + Ẩn Thẻ chính thức trong kết quả tìm kiếm + Nội dung trả phí được hiển thị + Nội dung trả phí đã ẩn + Ẩn Nội dung trả phí + Thẻ tự tài trợ được hiển thị + Thẻ tự tài trợ đã ẩn + Ẩn Thẻ tự tài trợ + Dải phân cách màu xám được hiển thị + Dải phân cách màu xám đã ẩn + Ẩn Dải phân cách màu xám + Đề xuất chung được hiển thị + Đề xuất chung đã ẩn + Ẩn Đề xuất chung + Phản ứng theo thời gian được hiển thị + Phản ứng theo thời gian đã ẩn + Ẩn Phản ứng theo thời gian + Bộ lọc người dùng đã tắt + Bộ lọc người dùng đang bật + Bật Bộ lọc người dùng + Xem biểu ngữ sản phẩm được hiển thị + Xem biểu ngữ sản phẩm đã ẩn + Ẩn Xem biểu ngữ sản phẩm + Bảng tìm kiếm trên web được hiển thị + Bảng tìm kiếm trên web đã ẩn + Ẩn Bảng tìm kiếm trên web + Thời lượng tối đa của video mà trình phát sẽ cố gắng lưu vào bộ đệm + Thời lượng bộ đệm tối đa + Thời lượng của video phải được đệm để bắt đầu phát hoặc tiếp tục phát sau một hành động của người dùng, chẳng hạn như tua video + Kích thước bộ đệm để bắt đầu phát video + Thời lượng của video phải được lưu vào bộ đệm để tiếp tục phát sau một lần đệm lại + Kích thước bộ đệm lại + Các tuỳ chọn cài đặt liên quan đến kích thước bộ đệm video + Cài đặt Bộ đệm video + Chọn độ phân giải video mặc định khi sử dụng Mạng di động + Chất lượng video mặc định khi sử dụng Mạng di động + Chọn độ phân giải video mặc định khi sử dụng Mạng Wi-Fi + Chất lượng video mặc định khi sử dụng Mạng Wi-Fi + Chọn tốc độ phát video mặc định + Tốc độ phát video mặc định + chưa được cài đặt. Hãy cài đặt và thử lại. + "Tên gói của ứng dụng Trình tải xuống, chẳng hạn như NewPipe hoặc PowerTube" + Tên gói của ứng dụng Trình tải xuống + Các tuỳ chọn cài đặt liên quan đến trình tải xuống mặc định + Cài đặt Trình tải xuống + Lớp phủ màn hình kết thúc được hiển thị + Lớp phủ màn hình kết thúc đã ẩn + Ẩn Lớp phủ màn hình kết thúc + Lớp phủ cuộn phim được hiển thị + Lớp phủ cuộn phim đã ẩn + Ẩn Lớp phủ cuộn phim + Phản hồi xúc giác khi đăng ký kênh đang bật + Phản hồi xúc giác khi đăng ký kênh đã tắt + Tắt Phản hồi xúc giác khi đăng ký kênh + Phản hồi xúc giác khi tua video đang bật + Phản hồi xúc giác khi tua video đã tắt + Tắt Phản hồi xúc giác khi tua video + Phản hồi xúc giác với các phân cảnh video đang bật + Phản hồi xúc giác với các phân cảnh video bị vô hiệu hóa + Tắt Phản hồi xúc giác với phân cảnh video + Tắt Phản hồi xúc giác khi nhấn giữ + Tắt Phản hồi xúc giác + Phản hồi xúc giác khi chụm để thu phóng đang bật + Phản hồi xúc giác khi chụm để thu phóng đã tắt + Tắt Phản hồi xúc giác khi chụm để thu phóng + Dấu thời gian đã được sao chép vào bảng nhớ tạm + Luôn tự động lặp lại đã tắt + Luôn tự động lặp lại đang bật + Luôn tự động lặp lại + Tắt cử chỉ vuốt khi lớp phủ điều khiển trình phát hiển thị + Luôn bật cử chỉ vuốt bất kể lớp phủ điều khiển trình phát có hiển thị hay không + Luôn bật Cử chỉ vuốt + Tốc độ phát tùy chỉnh đã tắt + Tốc độ phát tùy chỉnh đang bật + Bật Tốc độ phát tùy chỉnh + Trình duyệt bên ngoài ứng dụng đã tắt + Trình duyệt bên ngoài ứng dụng đang bật + Bật Trình duyệt bên ngoài ứng dụng + Độ sáng HDR tự động đã tắt + Độ sáng HDR tự động đang bật + Bật Độ sáng HDR tự động + Phát trong nền đã tắt + Phát trong nền đang bật + Bật Phát trong nền + Bố cục YouTube sẽ tuân theo trạng thái tài khoản Google của bạn + Đánh lừa phiên bản YouTube để bắt buộc bật bố cục cũ + Bật Bố cục cũ + Cài đặt chất lượng video kiểu mới được hiển thị + Cài đặt chất lượng video kiểu cũ được hiển thị + Bật bố cục Cài đặt chất lượng video kiểu cũ + Chuyển hướng URL (youtube.com/redirect) được sử dụng khi mở liên kết trong phần mô tả video + Bỏ qua chuyển hướng URL (youtube.com/redirect) khi mở liên kết trong phần mô tả video + Bật Cho phép mở liên kết trực tiếp + Nhấn để vuốt đã tắt + Nhấn để vuốt đang bật + Bật cử chỉ Nhấn để vuốt + Đánh lừa chỉ số DPI để sử dụng một số bố cục điện thoại + Bật Bố cục điện thoại + Chạm thanh tiến trình để tua video đã tắt + Không lưu chất lượng video đã chọn ngay cả khi bạn thay đổi chất lượng video + Lưu lại chất lượng video đã chọn bất cứ khi nào bạn thay đổi chất lượng video + Bật Lưu lại chất lượng video + Chạm thanh tiến trình để tua video đang bật + Bật Chạm thanh tiến trình để tua video + Ngay cả khi độ sáng được đặt thành 0 bằng cử chỉ vuốt, độ sáng tự động vẫn sẽ không được bật + Khi độ sáng được đặt thành 0 bằng cử chỉ vuốt, độ sáng tự động sẽ được bật + Bật cử chỉ Vuốt Độ sáng tự động + Vuốt Độ sáng đã tắt + Vuốt Độ sáng đang bật + Bật cử chỉ Vuốt Độ sáng + Phản hồi xúc giác khi nhấn để vuốt đã tắt + Phản hồi xúc giác khi nhấn để vuốt đang bật + Bật Phản hồi xúc giác khi nhấn để vuốt + Vuốt Âm lượng đã tắt + Vuốt Âm lượng đang bật + Bật cử chỉ Vuốt Âm lượng + Trình phát thu nhỏ của máy tính bảng đã tắt + Trình phát thu nhỏ của máy tính bảng đang bật + Bật Trình phát thu nhỏ của máy tính bảng + Đánh lừa chỉ số DPI để sử dụng một số bố cục máy tính bảng + Bật Bố cục máy tính bảng + Thanh tìm kiếm rộng đã tắt + Thanh tìm kiếm rộng đang bật + Bật Thanh tìm kiếm rộng + Tính năng thử nghiệm + Báo cáo lỗi, sự cố hoặc để lại góp ý tại đây + Trung tâm báo lỗi ReVanced Extended + Cài đặt ReVanced Extended + Các tuỳ chọn cài đặt mở rộng + Mở rộng + Sửa lỗi bộ đệm phát lại video đã tắt + Sửa lỗi bộ đệm phát lại video đang bật + Sửa lỗi Bộ đệm phát lại video + Phụ đề được bật khi phát video có phụ đề + "Phụ đề không được bật khi phát video có phụ đề" + Ẩn Phụ đề tự động + Bảng đa năng bật lên tự động khi phát video được hiển thị + Bảng đa năng bật lên tự động khi phát video đã ẩn + Ẩn Bảng đa năng bật lên tự động khi phát video + Nút Tự động phát được hiển thị + Nút Tự động phát đã ẩn + Ẩn nút Tự động phát + Ẩn các nút chức năng trong vùng chứa nút bên dưới video và trong video toàn màn hình + Ẩn Vùng chứa nút chức năng + Nút Tạo đoạn video được hiển thị + Nút Tạo đoạn video đã ẩn + Ẩn nút Tạo đoạn video + Nút Remix được hiển thị + Nút Remix đã ẩn + Ẩn nút Remix + Nút Không thích được hiển thị + Nút Không thích đã ẩn + Ẩn nút Không thích + Nút Tải xuống được hiển thị + Nút Tải xuống đã ẩn + Ẩn nút Tải xuống + Nút Thích được hiển thị + Nút Thích đã ẩn + Ẩn nút Thích + Nút Trò chuyện trực tiếp được hiển thị + Nút Trò chuyện trực tiếp đã ẩn + Ẩn nút Trò chuyện trực tiếp + Nút Lưu được hiển thị + Nút Lưu đã ẩn + Ẩn nút Lưu + Nút Báo vi phạm được hiển thị + Nút Báo vi phạm đã ẩn + Ẩn nút Báo vi phạm + Nút Chia sẻ được hiển thị + Nút Chia sẻ đã ẩn + Ẩn nút Chia sẻ + Nút Cảm ơn được hiển thị + Nút Cảm ơn đã ẩn + Ẩn nút Cảm ơn + Nút Phụ đề được hiển thị + Nút Phụ đề đã ẩn + Ẩn nút Phụ đề + Nút Truyền được hiển thị + Nút Truyền đã ẩn + Ẩn nút Truyền + Hình mờ cho video được hiển thị + Hình mờ cho video đã ẩn + Ẩn Hình mờ cho video + Ẩn Bình luận hoặc các thành phần liên quan đến tính năng Bình luận + Ẩn Bình luận hoặc các thành phần của Bình luận + Phần Bình luận được hiển thị + Phần Bình luận đã ẩn + Ẩn Bình luận + Nút Tạo được hiển thị + Nút Tạo đã ẩn + Ẩn nút Tạo + Hộp Chiến dịch gây quỹ được hiển thị + Hộp Chiến dịch gây quỹ đã ẩn + Ẩn hộp Chiến dịch gây quỹ + Địa chỉ email được hiển thị + Địa chỉ email đã ẩn + Ẩn Địa chỉ email + Màn hình kết thúc được hiển thị + Màn hình kết thúc đã ẩn + Ẩn Màn hình kết thúc + Vùng chứa nút trong video toàn màn hình được hiển thị + Vùng chứa nút trong video toàn màn hình đã ẩn + Ẩn Vùng chứa nút trong video toàn màn hình + Thẻ thông tin được hiển thị + Thẻ thông tin đã ẩn + Ẩn Thẻ thông tin + Menu Chế độ môi trường xung quanh được hiển thị + Menu Chế độ môi trường xung quanh đã ẩn + Ẩn menu Chế độ môi trường xung quanh + Menu Bản âm thanh được hiển thị + Menu Bản âm thanh đã ẩn + Ẩn menu Bản âm thanh + Menu Phụ đề được hiển thị + Menu Phụ đề đã ẩn + Ẩn menu Phụ đề + Menu Trợ giúp và phản hồi được hiển thị + Menu Trợ giúp và phản hồi đã ẩn + Ẩn menu Trợ giúp và phản hồi + Menu Các nút điều khiển trải nghiệm nghe được hiển thị + Menu Các nút điều khiển trải nghiệm nghe đã ẩn + Ẩn menu Các nút điều khiển trải nghiệm nghe + Menu Nghe bằng YouTube Music được hiển thị + Menu Nghe bằng YouTube Music đã ẩn + Ẩn menu Nghe bằng YouTube Music + Menu Cho video lặp lại được hiển thị + Menu Cho video lặp lại đã ẩn + Ẩn menu Cho video lặp lại + Menu Nội dung khác được hiển thị + Menu Nội dung khác đã ẩn + Ẩn menu Nội dung khác + Menu Báo vi phạm được hiển thị + Menu Báo vi phạm đã ẩn + Ẩn menu Báo vi phạm + Menu Thống kê chi tiết được hiển thị + Menu Thống kê chi tiết đã ẩn + Ẩn menu Thống kê chi tiết + Menu Xem ở chế độ thực tế ảo được hiển thị + Menu Xem ở chế độ thực tế ảo đã ẩn + Ẩn menu Xem ở chế độ thực tế ảo + Danh sách kết hợp được hiển thị + Danh sách kết hợp đã ẩn + Ẩn Danh sách kết hợp + Bộ lọc lớp phủ trình phát được hiển thị + Bộ lọc lớp phủ trình phát đã ẩn + Ẩn Bộ lọc lớp phủ trình phát + Xem trước bình luận hàng đầu được hiển thị + Xem trước bình luận hàng đầu đã ẩn + Ẩn Xem trước bình luận hàng đầu + Nút Shorts được hiển thị + Nút Shorts đã ẩn + Ẩn nút Shorts + Ẩn YouTube Shorts hoặc các thành phần liên quan đến trình phát Shorts + Ẩn YouTube Shorts và các thành phần của Shorts + Nút Bình luận trong trình phát Shorts được hiển thị + Nút Bình luận trong trình phát Shorts đã ẩn + Ẩn nút Bình luận trong trình phát Shorts + Ẩn YouTube Shorts và các thành phần của trình phát Shorts + Nút Phối lại trong trình phát Shorts được hiển thị + Nút Phối lại trong trình phát Shorts đã ẩn + Ẩn nút Phối lại trong trình phát Shorts + Nút Kênh đăng ký trong trình phát Shorts được hiển thị + Nút Kênh đăng ký trong trình phát Shorts đã ẩn + Ẩn nút Kênh đăng ký trong trình phát Shorts + Nút Mua ảnh động Super Thanks trong trình phát Shorts được hiển thị + Nút Mua ảnh động Super Thanks trong trình phát Shorts đã ẩn + Ẩn nút Mua ảnh động Super Thanks trong trình phát Shorts + Kệ Shorts được hiển thị + Kệ Shorts đã ẩn + Ẩn kệ Shorts + Phát YouTube Shorts khi khởi động ứng dụng đã tắt + Phát YouTube Shorts khi khởi động ứng dụng đang bật + Phát YouTube Shorts khi khởi động ứng dụng + Kệ Câu chuyện cá nhân được hiển thị + Kệ Câu chuyện cá nhân đã ẩn + Ẩn kệ Câu chuyện cá nhân + Hành động đề xuất được hiển thị + Hành động đề xuất đã ẩn + Ẩn Hành động đề xuất + Thời gian và Thanh tiến trình được hiển thị + Thời gian và Thanh tiến trình đã ẩn + Ẩn Thời gian và Thanh tiến trình + Cài đặt Bố cục bên dưới trình phát + Cài đặt Bố cục menu thả xuống + Cài đặt Bố cục toàn màn hình + Cài đặt Bố cục chung + Cài đặt Bố cục trình phát + Cài đặt Bố cục thanh tiến trình + Các tuỳ chọn cài đặt liên quan đến bố cục + Bố cục + Các tuỳ chọn cài đặt khác + Khác + Khác + Nút Tự động lặp lại đã ẩn + Nút Tự động lặp lại được hiển thị + Hiển thị nút Tự động lặp lại + Nút Sao chép liên kết đã ẩn + Nút Sao chép liên kết được hiển thị + Hiển thị nút Sao chép liên kết + Nút Sao chép liên kết với dấu thời gian đã ẩn + Nút Sao chép liên kết với dấu thời gian được hiển thị + Hiển thị nút Sao chép liên kết với dấu thời gian + Nút Tải xuống đã ẩn + Nút Tải xuống được hiển thị + Hiển thị nút Tải xuống + Các tuỳ chọn cài đặt liên quan đến nút trên lớp phủ trình phát video + Nút trên lớp phủ trình phát + Nút Danh sách cho phép đã ẩn + Nút Danh sách cho phép được hiển thị + Hiển thị nút Danh sách cho phép + Tiêu đề hiện tại: Tiêu đề mặc định + Tiêu đề hiện tại: Tiêu đề Premium + Tiêu đề Premium + Thông tin về bản vá được áp dụng + Thông tin bản vá + Ẩn thành phần của Bảng thả xuống trong cài đặt trình phát + Thành phần Bảng thả xuống của trình phát + "Vì đây vẫn là tính năng thử nghiệm nên có thể có các vấn đề chưa xác định khác. +Bạn có chắc chắn muốn tiếp tục không?" + "Đánh lừa thành phiên bản ứng dụng khách của YouTube v17.28.35 để tải bố cục cũ. + +Trong cài đặt ứng dụng, phiên bản YouTube có thể được đánh dấu là v17.28.35." + "Đánh lừa chỉ số DPI để thay đổi một số bố cục thành bố cục điện thoại. + +Nếu bạn bật tuỳ chọn này, các tính năng sau sẽ khả dụng: +- Bài đăng trên thẻ Cộng đồng. +- Ẩn Danh sách kết hợp." + "Khắc phục sự cố bộ đệm phát lại video ở một số khu vực. + +Nếu bạn bật tuỳ chọn này, sự cố trên sẽ được khắc phục, tuy nhiên có thể phát sinh vấn đề sau: +- Khi phát video trong danh sách phát, sự cố bộ đệm phát lại video có thể còn tồn đọng." + "Đánh lừa chỉ số DPI để thay đổi một số bố cục thành bố cục máy tính bảng. + +Nếu bạn bật tuỳ chọn này, các tính năng sau sẽ không khả dụng: +- Chế độ môi trường xung quanh. +- Bài đăng trên thẻ Cộng đồng." + Dữ liệu không thích được cung cấp bởi API True RYD Worker. Nhấn vào đây để tìm hiểu thêm. + true-ryd.cane.workers.dev + Mirror API đã tắt + Mirror API đang bật + Bật Mirror API + "API True RYD Worker sử dụng số lượt không thích được hiển thị trong Endpoint API YouTube. + +Chỉ bật tùy chọn này cho những người gặp sự cố khi sử dụng API RYD mặc định. + +Bạn có muốn tiếp tục không?" + True RYD Worker + Dữ liệu không thích được cung cấp bởi API Return YouTube Dislike. Nhấn vào đây để tìm hiểu thêm. + ReturnYouTubeDislike.com + Số lượt không thích được hiển thị dưới dạng số + Số lượt không thích được hiển thị dưới dạng phần trăm + Hiển thị số lượt không thích theo phần trăm + Số lượt không thích đã ẩn + Số lượt không thích được hiển thị + Hiển thị nút Không thích (RYD) + Số lượt không thích không khả dụng (đã đạt đến giới hạn API máy khách) + ReturnYouTubeDislike không thể xác nhận người dùng mới + ReturnYouTubeDislike không thể xác nhận bình chọn + Số lượt không thích tạm thời không khả dụng (API đã hết thời gian chờ) + ReturnYouTubeDislike không đăng ký được với tư cách người dùng mới + ReturnYouTubeDislike không gửi được bình chọn + Cài đặt Hiển thị nút Không thích + Hiển thị nút Không thích (RYD) + Cài đặt ReVanced + Các tuỳ chọn cài đặt liên quan đến điều khiển vuốt + Cài đặt Điều khiển vuốt + Độ rộng của ngưỡng vuốt để cử chỉ vuốt xảy ra + Độ rộng ngưỡng vuốt + Độ trong suốt của nền lớp phủ vuốt + Hiển thị nền lớp phủ vuốt + Kích thước văn bản trên lớp phủ vuốt + Kích thước văn bản lớp phủ vuốt + Số mili giây mà lớp phủ được hiển thị + Thời gian chờ lớp phủ vuốt + Công cụ sử dụng + Quảng cáo trên video được hiển thị + Quảng cáo trên video đã ẩn + Ẩn Quảng cáo trên video + Đặt chất lượng video thất bại + Không có kết nối mạng + Đã lưu chất lượng video trên mạng Di động thành: + Lưu chất lượng video trên mạng Di động thất bại + Đã lưu chất lượng video trên mạng Wi-Fi thành: + Lưu chất lượng video trên mạng Wi-Fi thất bại + Các tuỳ chọn cài đặt liên quan đến video + Video + Không thể thêm kênh %s vào danh sách cho phép %s + Kênh %s đã được thêm vào danh sách cho phép %s + Quảng cáo + Quảng cáo + Tên kênh + Không có kênh nào trong danh sách cho phép + Chưa được thêm vào danh sách cho phép + Đã thêm vào danh sách cho phép + Danh sách kênh cho phép + Truy xuất chi tiết kênh thất bại, đã nhận được mã %d + Khởi động lại để áp dụng cài đặt danh sách kênh cho phép + Loại bỏ kênh %s khỏi danh sách cho phép %s thất bại + Kênh %s đã bị loại bỏ khỏi danh sách cho phép %s + Kiểm tra hoặc xóa danh sách các kênh đã thêm vào danh sách cho phép + Cài đặt Danh sách cho phép + Tốc độ phát video + Tốc độ + SponsorBlock + SB + Máy chủ SponsorBlock không phản hồi! + Đã đọc + "Bạn nên đọc các nguyên tắc của tiện ích SponsorBlock trước khi gửi đi bất kì phân đoạn nào" + Hiển thị cho tôi + Đọc các nguyên tắc + Nguyên tắc bao gồm các mẹo về cách gửi phân đoạn + Xem các nguyên tắc + Cài đặt SponsorBlock + Các tuỳ chọn cài đặt liên quan đến tích hợp SponsorBlock + Đã chuyển đổi thành công. Hãy tải lại video! + Đang chuyển máy chủ API mirror sang máy chủ API chính.. + Màn hình kết thúc / Danh đề + Danh đề hoặc khi màn hình kết thúc của YouTube xuất hiện. Đoạn kết tĩnh + Phân đoạn lạc đề - nhảm nhí / Câu đùa hài hước + Các cảnh tiếp theo chỉ được thêm vào để bổ sung không bắt buộc để hiểu nội dung chính của video. Điều này không nên bao gồm các phân đoạn cung cấp các chi tiết bối cảnh hoặc nền + Tạm dừng / Giới thiệu + Khoảng thời gian không có nội dung thực tế. Có thể là sự tạm dừng, khung hình tĩnh, hoạt cảnh lặp lại + Âm nhạc: Phần không phải âm nhạc + Chỉ sử dụng trong video âm nhạc. Bỏ qua các phần video không có trong bản mix chính thức + Xem trước / Tóm tắt + "Tóm tắt các tập trước đó hay xem trước những gì sẽ xảy ra trong video hiện tại hoặc các video tiếp theo trong cùng một chuỗi video (series) dài. Các clip không nên cung cấp thêm thông tin." + Quảng cáo không được trả phí / Tự quảng cáo + Khi có quảng cáo chưa thanh toán hoặc tự quảng cáo. Điều này bao gồm các phần hàng hóa, khoản quyên góp hoặc thông tin về những người họ đã cộng tác + Nhà tài trợ + Quảng cáo, giới thiệu được trả phí và quảng cáo trực tiếp + Nhắc nhở tương tác (Đăng ký kênh) + Khi có lời nhắc ngắn hãy thích, đăng ký, theo dõi hoặc tương tác với họ trên bất kỳ nền tảng miễn phí hoặc trả phí nào + Xuất cài đặt thất bại + Nhập / Xuất cài đặt + Đây là toàn bộ thiết đặt cấu hình của bạn và có thể áp dụng trong tiện ích mở rộng của máy tính dưới dạng JSON. Nó bao gồm cả ID người dùng của bạn, vì thế hãy thận trọng khi chia sẻ nó. + Nhập cài đặt thất bại + Cài đặt đã được nhập thành công + Tự động bỏ qua + Tự động bỏ qua một lần + "Đừng làm gì cả" + Hiển thị nút Bỏ qua phân đoạn + Bỏ qua phân đoạn + Đã bỏ qua kết thúc + Đã bỏ qua phân đoạn lạc đề - nhảm nhí + Đã bỏ qua giới thiệu + Đã bỏ qua phần không phải âm nhạc + Đã bỏ qua xem trước + Đã bỏ qua một phân đoạn nhà tài trợ + Đã bỏ qua tự quảng cáo + Đã bỏ qua nhà tài trợ + Đã bỏ qua nhắc nhở tương tác + Đã bỏ qua phân đoạn chưa gửi + Thống kê + Đang tải.. + "Bạn đã giúp mọi người bỏ qua <b>%s</b> phân đoạn." + "Tương đương với <b>%s</b> trong cuộc đời họ. Nhấn để xem bảng xếp hạng" + SponsorBlock đã tắt + "Bạn đã bỏ qua <b>%s</b> phân đoạn." + "Tổng thời gian là <b>%s</b>." + Số phân đoạn đã gửi: <b>%s</b> + Tên người dùng của bạn: <b>%s</b> + Nhấn để thay đổi tên người dùng của bạn + Không thay đổi được tên người dùng: Trạng thái: %d %s + Tên người dùng đã được thay đổi thành công + "Không thể gửi phân đoạn. +Đã tồn tại" + "Không thể gửi phân đoạn. + +%s" + "Không thể gửi phân đoạn. +Giới hạn truy cập (Quá nhiều truy cập từ cùng một người dùng hoặc IP)" + Không thể gửi phân đoạn: %s + Không gửi được phân đoạn: Trạng thái: %d %s + Đang gửi phân đoạn… + Phân đoạn được gửi thành công + Nhấn để bỏ qua + Thay đổi danh mục + Phản đối + "Không thể bình chọn cho phân đoạn. + +%s" + "Không thể bình chọn cho phân đoạn. +Giới hạn truy cập (Quá nhiều truy cập từ cùng một người dùng hoặc IP)" + Không bình chọn được cho phân đoạn: Trạng thái: %d%s + Không có phân đoạn nào để bình chọn + Đang bình chọn… + Bình chọn thành công + Ủng hộ + diff --git a/src/main/resources/youtube/translations/zh-rCN/strings.xml b/src/main/resources/youtube/translations/zh-rCN/strings.xml new file mode 100644 index 000000000..8cd6b2728 --- /dev/null +++ b/src/main/resources/youtube/translations/zh-rCN/strings.xml @@ -0,0 +1,617 @@ + + + 关于 + 此应用使用来自 SponsorBlock 的 API + 点击了解更多信息,并查看其他平台的下载:sponsor.ajay.app + 由 JakubWeg 进行合并 + 是否打开视频播放器的无障碍控制? + 由于无障碍服务已启用,您的控制被修改。 + API 地址已更改 + 提供的 API 地址无效 + 重置 API 地址 + API 镜像地址已更改 + 提供的 API 镜像地址无效 + 重置 API 镜像地址 + 想要更改类别颜色吗? + "您可以通过点击上方的类别更改颜色。" + 颜色已更改 + 十六进制代码无效 + 重置颜色 + 如何处理不同片段 + 启用 SponsorBlock + SponsorBlock 是一个众包平台,旨在帮助人们跳过 YouTube 视频中烦人的部分 + 启用 SponsorBlock 镜像 + 当 SponsorBlock API 服务器宕机时,切换镜像 API 服务器为默认 API 服务器 + 启用新的片段添加 + 开启此选项以启用片段添加实验性功能(有按钮可见性问题) + 启用投票 + 开启此选项以启用投票 + 常规设置 + 调整新片段的间距 + 这是您在添加新片段时使用时间调整按钮可以移动的时长(毫秒) + 更改 API 地址 + "SponsorBlock 用于调用的服务器地址。<b>除非您知道自己在做什么,否则不要改变这个地址。</b>" + 更改 API 镜像地址 + "镜像服务器地址用于当 SponsorBlock 服务器宕机的切换。<b>除非您知道自己在做什么,否则不要改变这个地址。</b>" + 最短片段时长 + 短于设定时长(秒)的片段将不会跳过或显示在播放器中 + 监测跳过计数 + 这让 SponsorBlock 排行榜系统知道人们节省了多少时间。每次跳过一个片段时,扩展都会向服务器发送一条信息 + 自动跳过片段时显示提示 + 点击查看示例提示 + 显示去除片段剩余的时长 + 此时长会显示在当前时长旁边的括号中。这表示视频总时长减去所有片段时长。 + 您的私人用户 ID + 这应该保密。就像密码一样,不应该泄露给任何人。如果他人获得了这个 ID,他们可以冒充您 + 请安装 MicroG + 未找到 MicroG + 通知设置 + "1. Google 设备注册和云端推送(GCM)需要被打开以接收通知。 +2. ReVanced 需要在 GCM 下显示已注册。 +3. GCM 的目前状态应为已连接。" + MicroG 设置 + + 选择片段类别 + "片段从 %02d:%02d 到 %02d:%02d(%d 分 %02d 秒) +是否确认提交?" + 时间是否正确? + "您在设置中禁用了此类别,启用该项才能提交" + 您想要编辑片段开始或结束的时间吗? + 给定的时间无效 + 已完成 + 手动编辑片段时间 + 结束 + 先在进度条标记两个位置 + 开始 + 设置 %02d:%02d:%04d 作为新片段的开始或结束? + 现在 + 片段结束时间 + 设定片段的结束 + 片段开始时间 + 设定片段的开始 + 新的 SponsorBlock 片段 + 重置 + 广告相关设置 + 广告设置 + 搜索结果中的专辑卡片已显示 + 搜索结果中的专辑卡片已隐藏 + 专辑卡片 + 突发新闻面板已显示 + 突发新闻面板已隐藏 + 突发新闻面板 + 按钮广告已显示 + 按钮广告已隐藏 + 按钮广告 + 频道指南已显示 + 频道指南已隐藏 + 频道指南 + 章节预告已显示 + 章节预告已隐藏 + 视频下方的章节预告 + 社区指南已显示 + 社区指南已隐藏 + 社区指南 + 社区帖子已显示 + 社区帖子已隐藏 + 社区帖子 + 紧凑横幅已显示 + 紧凑横幅已隐藏 + 紧凑横幅 + 用逗号隔开组件按其名称筛选 + 自定义筛选 + 应急箱已显示 + 应急箱已隐藏 + 应急箱 + 一般广告已显示 + 一般广告已隐藏 + 一般广告 + 图片功能架已显示 + 图片功能架已隐藏 + 图片功能架 + 信息面板已显示 + 信息面板已隐藏 + 信息面板 + 问卷调查已显示 + 问卷调查已隐藏 + 问卷调查 + 最新帖子已显示 + 最新帖子已隐藏 + 最新帖子 + 医疗面板已显示 + 医疗面板已隐藏 + 医疗面板 + 商品横幅已显示 + 商品横幅已隐藏 + 商品横幅 + 电影面板已显示 + 电影面板已隐藏 + 电影面板 + 搜索结果中的官方卡片(音乐、游戏等)已显示 + 搜索结果中的官方卡片(音乐、游戏等)已隐藏 + 官方卡片 + 付费内容已显示 + 付费内容已隐藏 + 付费内容 + 自我推广卡片已显示 + 自我推广卡片已隐藏 + 自我推广卡片 + 灰色分隔符已显示 + 灰色分隔符已隐藏 + 灰色分隔符 + 建议已显示 + 建议已隐藏 + 建议 + (评论)时间跳转已显示 + (评论)时间跳转已隐藏 + 时间跳转 + 用户过滤已禁用 + 用户过滤已启用 + 用户过滤 + 视图产品横幅已显示 + 视图产品横幅已隐藏 + 视图产品横幅 + 网页搜索面板已显示 + 网页搜索面板已隐藏 + 网页搜索面板 + 播放器尝试缓冲视频的最大时长 + 缓冲区最大时长 + 在用户操作(如搜索)后,开始或恢复播放视频的缓冲区时长 + 播放开始缓冲区时长 + 重新缓冲后,恢复播放视频的缓冲区时长 + 重新缓冲区时长 + 视频缓冲区大小相关设置 + 视频缓冲区设置 + 选择移动网络上默认的视频分辨率 + 移动网络上的默认视频画质 + 选择 Wi-Fi 网络上的默认视频分辨率 + WiFi 网络上的默认视频画质 + 选择默认播放速度 + 默认播放速度 + 未安装,请先安装。 + "下载器的应用包名,例如 NewPipe 的或 PowerTube 的" + 下载器的应用包名 + 默认下载器相关设置 + 下载器设置 + 结束界面叠加层已显示 + 结束界面叠加层已隐藏 + 结束界面叠加层 + 影片条叠加层已显示 + 影片条叠加层已隐藏 + 视频条叠加层 + 滑动触感反馈已启用 + 滑动触感反馈已禁用 + 滑动触感反馈 + 进度触感反馈已启用 + 进度触感反馈已禁用 + 进度触感反馈 + 章节触感反馈已启用 + 章节触感反馈已禁用 + 章节触感反馈 + 禁用长按触感反馈 + 触感反馈 + 缩放触感反馈已启用 + 缩放触感反馈已禁用 + 缩放触感反馈 + 时间戳已复制到剪贴板 + 始终自动循环播放已禁用 + 始终自动循环播放已启用 + 始终自动循环播放 + 显示播放控制时,禁用滑动手势 + 无论播放控制显示与否,总是启用滑动手势 + 滑动手势 + 自定义播放速度已禁用 + 自定义播放速度已启用 + 自定义播放速度 + 外部浏览器已禁用 + 外部浏览器已启用 + 外部浏览器 + HDR 视频自动亮度已禁用 + HDR 视频自动亮度已启用 + HDR 视频自动亮度 + 最小化播放已禁用 + 最小化播放已启用 + 最小化播放 + YouTube 布局将会跟随您的 Google 账号状态 + 伪装 YouTube 版本以启用禁用旧布局 + 启用旧布局 + 新版画质设置已显示 + 旧版画质设置已显示 + 旧版画质布局 + 当前打开视频描述中的链接时,使用重定向(youtube.com/redirect) + 当前打开视频描述中的链接时,绕过重定向(youtube.com/redirect)直接打开 + 直接打开链接 + 长按以滑动已禁用 + 长按以滑动已启用 + 长按以滑动手势 + 伪装 DPI 以使用一些手机布局 + 启用手机布局 + 进度条点击已禁用 + 修改视频画质时不保存为默认画质 + 修改视频画质时保存为默认画质 + 保存视频画质 + 进度条点击已启用 + 进度条点击 + 即使滑动亮度设置为0,也不启用自动亮度 + 当滑动亮度设置为0,启用自动亮度 + 滑动自动亮度 + 滑动控制亮度已禁用 + 滑动控制亮度已启用 + 亮度手势 + 长按以滑动触感反馈已禁用 + 长按以滑动触感反馈已启用 + 长按以滑动触感反馈 + 滑动控制音量已禁用 + 滑动控制音量已启用 + 音量手势 + 平板迷你播放器已禁用 + 平板迷你播放器已启用 + 平板迷你播放器 + 伪装 DPI 以使用一些平板布局 + 启用平板布局 + 宽搜索栏已禁用 + 宽搜索栏已启用 + 宽搜索栏 + 实验性功能 + 在此报告问题或留下建议 + ReVanced Extended 问题中心 + ReVanced Extended 设置 + Extended 相关设置 + Extended 设置 + 修复视频播放缓冲问题已关闭 + 修复视频播放缓冲问题已开启 + 修复视频缓冲问题 + 强制播放有字幕的视频时启用字幕 + "强制播放有字幕的视频时禁用字幕" + 自动字幕 + 自动播放器弹出面板已显示 + 自动播放器弹出面板已隐藏 + 自动播放器弹出面板 + 自动播放按钮已显示 + 自动播放按钮已隐藏 + 自动播放按钮 + 隐藏按钮栏的组件 + 按钮栏组件 + 剪辑按钮已显示 + 剪辑按钮已隐藏 + 剪辑按钮 + 制作按钮已显示 + 制作按钮已隐藏 + 制作按钮 + 点踩按钮已显示 + 点踩按钮已隐藏 + 点踩按钮 + 下载按钮已显示 + 下载按钮已隐藏 + 下载按钮 + 点赞按钮已显示 + 点赞按钮已隐藏 + 点赞按钮 + 实时聊天按钮已显示 + 实时聊天按钮已隐藏 + 实时聊天按钮 + 保存(到播放列表)按钮已显示 + 保存(到播放列表)按钮已隐藏 + 保存按钮 + 举报按钮已显示 + 举报按钮已隐藏 + 举报按钮 + 分享按钮已显示 + 分享按钮已隐藏 + 分享按钮 + 感谢按钮已显示 + 感谢按钮已隐藏 + 感谢按钮 + 字幕按钮已显示 + 字幕按钮已隐藏 + 字幕按钮 + 投屏按钮已显示 + 投屏按钮已隐藏 + 投屏按钮 + 频道水印已显示 + 频道水印已隐藏 + 频道水印 + 隐藏评论部分或组件 + 评论组件 + 评论部分已显示 + 评论部分已隐藏 + 评论部分 + 创建按钮已显示 + 创建按钮已隐藏 + 创建按钮 + 众筹箱已显示 + 众筹箱已隐藏 + 众筹箱 + 邮件地址已显示 + 邮件地址已隐藏 + 邮件地址 + 结束界面卡片已显示 + 结束界面卡片已隐藏 + 结束界面卡片 + 全屏按钮栏已显示 + 全屏按钮栏已隐藏 + 全屏按钮栏 + 资料卡已显示 + 资料卡已隐藏 + 资料卡 + 设置项「氛围模式」已显示 + 设置项「氛围模式」已隐藏 + 设置项「氛围模式」 + 设置项「仅播放音频」已显示 + 设置项「仅播放音频」已隐藏 + 设置项「仅播放音频」 + 设置项「字幕」已显示 + 设置项「字幕」已隐藏 + 设置项「字幕」 + 设置项「帮助和反馈」已显示 + 设置项「帮助和反馈」已隐藏 + 设置项「帮助和反馈」 + 设置项「听力控制」已显示 + 设置项「听力控制」已隐藏 + 设置项「听力控制」 + 设置项「使用 YouTube Music 收听」已显示 + 设置项「使用 YouTube Music 收听」已隐藏 + 设置项「使用 YouTube Music 收听」 + 设置项「循环播放视频」已显示 + 设置项「循环播放视频」已隐藏 + 设置项「循环播放视频」 + 设置项「来自××的更多内容」已显示 + 设置项「来自××的更多内容」已隐藏 + 设置项「来自××的更多内容」 + 设置项「举报」已显示 + 设置项「举报」已隐藏 + 设置项「举报」 + 设置项「系统管理员统计」已显示 + 设置项「系统管理员统计」已隐藏 + 设置项「系统管理员统计」 + 设置项「在 VR 模式下观看」已显示 + 设置项「在 VR 模式下观看」已隐藏 + 设置项「在 VR 模式下观看」 + 合辑播放列表已显示 + 合辑播放列表已隐藏 + 合辑播放列表 + 播放器叠加层过滤器已显示 + 播放器叠加层过滤器已隐藏 + 播放器叠加层过滤器 + 预览评论已显示 + 预览评论已隐藏 + 预览评论 + Shorts 按钮已显示 + Shorts 按钮已隐藏 + Shorts 按钮 + 隐藏 Shorts 部分或 Shorts 播放器组件 + Shorts 播放器组件 + 评论按钮已显示 + 评论按钮已隐藏 + 评论按钮 + Shorts 播放器组件 + 混剪按钮已显示 + 混剪按钮已隐藏 + 混剪按钮 + 订阅按钮已显示 + 订阅按钮已隐藏 + 订阅按钮 + 感谢按钮已显示 + 感谢按钮已隐藏 + 感谢按钮 + Shorts 功能架已显示 + Shorts 功能架已隐藏 + Shorts 功能架 + 应用启动时 Shorts 播放器已禁用 + 应用启动时 Shorts 播放器已启用 + 应用启动时的 Shorts 播放器 + 短片故事部分已显示 + 短片故事部分已隐藏 + 短片故事部分 + 操作建议已显示 + 操作建议已隐藏 + 操作建议 + 时长和进度条已显示 + 时长和进度条已隐藏 + 时长和进度条 + 底部播放器布局设置 + 悬浮菜单布局设置 + 全屏布局设置 + 一般布局设置 + 播放器布局设置 + 进度条布局设置 + 布局相关设置 + 布局设置 + 其他相关设置 + 其他设置 + 其他 + 自动循环播放按钮已隐藏 + 自动循环播放按钮已显示 + 自动循环播放按钮 + 复制链接按钮已隐藏 + 复制链接按钮已显示 + 复制链接按钮 + 带时间戳复制链接按钮已隐藏 + 带时间戳复制链接按钮已显示 + 带时间戳复制链接按钮 + 下载按钮已隐藏 + 下载按钮已显示 + 下载按钮 + 叠加层按钮相关设置 + 叠加层按钮设置 + 白名单按钮已隐藏 + 白名单按钮已显示 + 白名单按钮 + 当前页眉:默认标志 + 当前页眉:Premium 标志 + Premium 标志 + 已应用补丁信息 + 补丁信息 + 隐藏悬浮面板的播放器设置组件 + 播放器悬浮面板组件 + "由于这仍然是一个实验性功能,可能还有其他未知问题。 +您确定要继续吗?" + "伪装 YouTube 客户端版本为 v17.28.35 以载入旧布局 + +在应用设置里,YouTube 版本可能会显示为 v17.28.35" + "伪装 DPI 将一些布局改为手机样式。 + +如果启用该设置,可以使用以下功能: +- 社区帖子 +- 隐藏合辑播放列表" + "修复某些地区存在的视频播放缓冲问题。 + +如果启用该设置,可能会出现以下问题: +- 当播放列表中的视频时,该问题可能不会被修复" + "伪装 DPI 将一些布局改为平板样式。 + +如果启用该设置,以下功能不可用: +- 氛围模式 +- 社区帖子" + 点踩数据由 True RYD Worker API 提供。点击了解更多信息。 + true-ryd.cane.workers.dev + 镜像 API 已禁用 + 镜像 API 已启用 + 镜像 API + "True RYD Worker API 使用的点踩计数来自公开的 YouTube API 端口。 + +仅当使用默认的 RYD API 出现问题时启用这个选项。 + +是否继续?" + True RYD Worker + 点踩数据由 Return YouTube Dislike API 提供。点击了解更多信息。 + ReturnYouTubeDislike.com + 点踩显示为数字 + 点踩显示为百分比 + 点踩百分比 + 点踩数已隐藏 + 点踩数已显示 + 恢复 YouTube 点踩 + 点踩数不可用(已达到客户端 API 限制) + ReturnYouTubeDislike 无法确认新用户 + ReturnYouTubeDislike 无法确认投票 + 点踩数暂时不可用(API 连接超时) + ReturnYouTubeDislike 无法注册为新用户 + ReturnYouTubeDislike 无法发送投票 + 恢复 YouTube 点踩设置 + 恢复 YouTube 点踩 + ReVanced 设置 + 滑动控制相关设置 + 滑动控制设置 + 防误触的滑动幅度阈值 + 滑动幅度阈值 + 滑动叠加层背景透明度 + 滑动背景透明度 + 滑动叠加层上的文本大小 + 滑动叠加层上的文本大小 + 滑动叠加层显示的时长(毫秒) + 滑动叠加层时长 + 使用的工具 + 视频广告已显示 + 视频广告已隐藏 + 视频广告 + 设置画质失败 + 无网络连接 + 更改移动网络的默认画质为: + 更改移动网络的默认画质失败 + 更改 WiFi 的默认画质为: + 更改 WiFi 的默认画质失败 + 视频相关设置 + 视频设置 + 无法将频道 %s 添加到 %s 白名单 + 频道 %s 已添加到 %s 白名单 + 视频广告 + 广告 + 频道名称 + 无白名单频道 + 未添加到白名单 + 已添加到白名单 + 频道白名单 + 获取频道详情失败,错误代码 %d + 重启以应用频道白名单设置 + 无法将频道 %s 从 %s 白名单移除 + 频道 %s 已从 %s 白名单移除 + 检查或移除已添加到白名单的频道列表 + 白名单设置 + 播放速度 + 速度 + SponsorBlock + SB + SponsorBlock 服务器没有响应! + 已读 + "建议在提交任何片段前阅读 SponsorBlock 指南" + 显示给我 + 已有指南 + 指南中包含关于提交片段的提示和规则 + 查看指南 + SponsorBlock 设置 + SponsorBlock 相关设置 + 已成功切换,重新加载视频 + 正在切换镜像 API 服务器为主 API 服务器… + 结束画面/演职员表 + 当演职员表或出现 YouTube 结束画面时。不适用于语音结尾 + 灌水内容/笑话 + 灌水片段,例如闲聊或幽默,对理解视频主要内容并无帮助。这不会包含叙述环境与背景信息。 + 过场/开场动画 + 没有实际内容的间隔。可能是暂停、静态画面、重复动画 + 音乐:非音乐部分 + 仅用于音乐视频。跳过官方组合未包含的视频部分 + 预告/回顾 + "前面剧集的回顾或后面剧集的预告。剪辑不应提供额外信息" + 无偿广告/自我推销 + 当有无偿广告或自我推销时。 这包括有关商品、捐赠或与他人合作的信息的具体部分 + 赞助商 + 付费宣传、付费推荐和广告 + 交互提醒(订阅) + 当在任何免费或付费平台上出现点赞、订阅、关注或与他们交互的简短提醒时 + 导出设置失败 + 导入/导出设置 + 这是存有您完整配置并适用于桌面扩展的 JSON。 其中包括您的私人用户 ID,因此请务必谨慎分享。 + 导入设置失败 + 导入设置成功 + 自动跳过 + 自动跳过一次 + "忽略" + 显示跳过按钮 + 跳过片段 + 已跳过视频结尾 + 已跳过灌水片段 + 已跳过开场动画 + 已跳过非音乐部分 + 已跳过预告 + 已跳过赞助商片段 + 已跳过自我推广 + 已跳过赞助商广告 + 已跳过烦人提醒 + 已跳过未提交片段 + 统计 + 加载中... + "您帮人们保存了 <b>%s</b> 个片段。" + "那是他们生命中的 <b>%s</b> 。点击查看排行榜" + SponsorBlock 已禁用 + "您已跳过 <b>%s</b> 个片段。" + "总计 <b>%s</b>。" + 提交数:<b>%s</b> + 您的用户名:<b>%s</b> + 点击更改您的用户名 + 无法更改用户名,状态:%d %s + 用户名修改成功 + "无法提交片段。 +片段已经存在" + "无法提交片段。 + +%s" + "无法提交片段。 +频率受限(来自同一用户或 IP 次数过多)" + 无法提交片段:%s + 无法提交片段,状态:%d %s + 正在提交片段… + 片段提交成功 + 点击跳过 + 更改类别 + 反对票 + "无法为片段投票。 + +%s" + "无法为片段投票。 +频率受限(来自同一用户或 IP 次数过多)" + 无法对片段进行投票,状态: %d %s + 没有可供投票的片段 + 正在为片段投票… + 投票成功 + 赞成票 +