mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-04-30 06:34:37 +02:00
Merge branch 'dev' into revanced-extended
This commit is contained in:
commit
ae69aca189
88
README.md
88
README.md
@ -15,7 +15,7 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm
|
|||||||
| `Ambient mode control` | Adds options to disable Ambient mode and to bypass Ambient mode restrictions. | 18.29.38 ~ 19.44.39 |
|
| `Ambient mode control` | Adds options to disable Ambient mode and to bypass Ambient mode restrictions. | 18.29.38 ~ 19.44.39 |
|
||||||
| `Bypass URL redirects` | Adds an option to bypass URL redirects and open the original URL directly. | 18.29.38 ~ 19.44.39 |
|
| `Bypass URL redirects` | Adds an option to bypass URL redirects and open the original URL directly. | 18.29.38 ~ 19.44.39 |
|
||||||
| `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 18.29.38 ~ 19.44.39 |
|
| `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 18.29.38 ~ 19.44.39 |
|
||||||
| `Change layout` | Adds an option to change the dp in order to use a tablet or phone layout. | 18.29.38 ~ 19.44.39 |
|
| `Change form factor` | Adds an option to change the UI appearance to a phone, tablet, or automotive device. | 18.29.38 ~ 19.44.39 |
|
||||||
| `Change live ring click action` | Adds an option to open the channel instead of the live stream when clicking on the live ring. | 18.29.38 ~ 19.44.39 |
|
| `Change live ring click action` | Adds an option to open the channel instead of the live stream when clicking on the live ring. | 18.29.38 ~ 19.44.39 |
|
||||||
| `Change player flyout menu toggles` | Adds an option to use text toggles instead of switch toggles within the additional settings menu. | 18.29.38 ~ 19.44.39 |
|
| `Change player flyout menu toggles` | Adds an option to use text toggles instead of switch toggles within the additional settings menu. | 18.29.38 ~ 19.44.39 |
|
||||||
| `Change share sheet` | Adds an option to change the in-app share sheet to the system share sheet. | 18.29.38 ~ 19.44.39 |
|
| `Change share sheet` | Adds an option to change the in-app share sheet to the system share sheet. | 18.29.38 ~ 19.44.39 |
|
||||||
@ -84,48 +84,49 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm
|
|||||||
|
|
||||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||||
|:--------:|:--------------:|:-----------------:|
|
|:--------:|:--------------:|:-----------------:|
|
||||||
| `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 6.20.51 ~ 8.05.51 |
|
| `Bitrate default value` | Sets the audio quality to 'Always High' when you first install the app. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 6.20.51 ~ 8.05.51 |
|
| `Bypass image region restrictions` | Adds an option to use a different host for static images, so that images blocked in some countries can be received. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.20.51 ~ 8.05.51 |
|
| `Certificate spoof` | Enables YouTube Music to work with Android Auto by spoofing the YouTube Music certificate. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Change share sheet` | Adds an option to change the in-app share sheet to the system share sheet. | 6.20.51 ~ 8.05.51 |
|
| `Change share sheet` | Adds an option to change the in-app share sheet to the system share sheet. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Change start page` | Adds an option to set which page the app opens in instead of the homepage. | 6.20.51 ~ 8.05.51 |
|
| `Change start page` | Adds an option to set which page the app opens in instead of the homepage. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Custom branding icon for YouTube Music` | Changes the YouTube Music app icon to the icon specified in patch options. | 6.20.51 ~ 8.05.51 |
|
| `Custom branding icon for YouTube Music` | Changes the YouTube Music app icon to the icon specified in patch options. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Custom branding name for YouTube Music` | Changes the YouTube Music app name to the name specified in patch options. | 6.20.51 ~ 8.05.51 |
|
| `Custom branding name for YouTube Music` | Changes the YouTube Music app name to the name specified in patch options. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Custom header for YouTube Music` | Applies a custom header in the top left corner within the app. | 6.20.51 ~ 8.05.51 |
|
| `Custom header for YouTube Music` | Applies a custom header in the top left corner within the app. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Dark theme` | Changes the app's dark theme to the values specified in patch options. | 6.20.51 ~ 8.05.51 |
|
| `Dark theme` | Changes the app's dark theme to the values specified in patch options. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Disable Cairo splash animation` | Adds an option to disable Cairo splash animation. | 7.06.54 ~ 8.05.51 |
|
| `Disable Cairo splash animation` | Adds an option to disable Cairo splash animation. | 7.06.54 ~ 8.10.51 |
|
||||||
| `Disable DRC audio` | Adds an option to disable DRC (Dynamic Range Compression) audio. | 6.20.51 ~ 8.05.51 |
|
| `Disable DRC audio` | Adds an option to disable DRC (Dynamic Range Compression) audio. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Disable QUIC protocol` | Adds an option to disable CronetEngine's QUIC protocol. | 6.20.51 ~ 8.05.51 |
|
| `Disable QUIC protocol` | Adds an option to disable CronetEngine's QUIC protocol. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Disable dislike redirection` | Adds an option to disable redirection to the next track when clicking the Dislike button. | 6.20.51 ~ 8.05.51 |
|
| `Disable dislike redirection` | Adds an option to disable redirection to the next track when clicking the Dislike button. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Disable forced auto captions` | Adds an option to disable captions from being automatically enabled. | 6.20.51 ~ 8.05.51 |
|
| `Disable forced auto captions` | Adds an option to disable captions from being automatically enabled. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Disable music video in album` | Adds option to redirect music videos from albums for non-premium users. | 6.20.51 ~ 8.05.51 |
|
| `Disable music video in album` | Adds option to redirect music videos from albums for non-premium users. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Enable OPUS codec` | Adds an option to enable the OPUS audio codec if the player response includes it. | 6.20.51 ~ 8.05.51 |
|
| `Enable OPUS codec` | Adds an option to enable the OPUS audio codec if the player response includes it. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Enable debug logging` | Adds an option to enable debug logging. | 6.20.51 ~ 8.05.51 |
|
| `Enable debug logging` | Adds an option to enable debug logging. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.20.51 ~ 8.05.51 |
|
| `Enable landscape mode` | Adds an option to enable landscape mode when rotating the screen on phones. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Flyout menu components` | Adds options to hide or change flyout menu components. | 6.20.51 ~ 8.05.51 |
|
| `Flyout menu components` | Adds options to hide or change flyout menu components. | 6.20.51 ~ 8.10.51 |
|
||||||
| `GmsCore support` | Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services. | 6.20.51 ~ 8.05.51 |
|
| `GmsCore support` | Allows patched Google apps to run without root and under a different package name by using GmsCore instead of Google Play Services. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Hide account components` | Adds options to hide components related to the account menu. | 6.20.51 ~ 8.05.51 |
|
| `Hide account components` | Adds options to hide components related to the account menu. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Hide action bar components` | Adds options to hide action bar components and replace the offline download button with an external download button. | 6.20.51 ~ 8.05.51 |
|
| `Hide action bar components` | Adds options to hide action bar components and replace the offline download button with an external download button. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Hide ads` | Adds options to hide ads. | 6.20.51 ~ 8.05.51 |
|
| `Hide ads` | Adds options to hide ads. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Hide layout components` | Adds options to hide general layout components. | 6.20.51 ~ 8.05.51 |
|
| `Hide layout components` | Adds options to hide general layout components. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Hide overlay filter` | Removes, at compile time, the dark overlay that appears when player flyout menus are open. | 6.20.51 ~ 8.05.51 |
|
| `Hide overlay filter` | Removes, at compile time, the dark overlay that appears when player flyout menus are open. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Hide player overlay filter` | Removes, at compile time, the dark overlay that appears when single-tapping in the player. | 6.20.51 ~ 8.05.51 |
|
| `Hide player overlay filter` | Removes, at compile time, the dark overlay that appears when single-tapping in the player. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Navigation bar components` | Adds options to hide or change components related to the navigation bar. | 6.20.51 ~ 8.05.51 |
|
| `Navigation bar components` | Adds options to hide or change components related to the navigation bar. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Player components` | Adds options to hide or change components related to the player. | 6.20.51 ~ 8.05.51 |
|
| `Player components` | Adds options to hide or change components related to the player. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Remove background playback restrictions` | Removes restrictions on background playback, including for kids videos. | 6.20.51 ~ 8.05.51 |
|
| `Remove background playback restrictions` | Removes restrictions on background playback, including for kids videos. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Remove viewer discretion dialog` | Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction. | 6.20.51 ~ 8.05.51 |
|
| `Remove viewer discretion dialog` | Adds an option to remove the dialog that appears when opening a video that has been age-restricted by accepting it automatically. This does not bypass the age restriction. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Restore old style library shelf` | Adds an option to return the Library tab to the old style. | 6.20.51 ~ 8.05.51 |
|
| `Restore old style library shelf` | Adds an option to return the Library tab to the old style. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Return YouTube Dislike` | Adds an option to show the dislike count of songs using the Return YouTube Dislike API. | 6.20.51 ~ 8.05.51 |
|
| `Return YouTube Dislike` | Adds an option to show the dislike count of songs using the Return YouTube Dislike API. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Return YouTube Username` | Adds an option to replace YouTube handles with usernames in comments using YouTube Data API v3. | 6.20.51 ~ 8.05.51 |
|
| `Return YouTube Username` | Adds an option to replace YouTube handles with usernames in comments using YouTube Data API v3. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Sanitize sharing links` | Adds an option to sanitize sharing links by removing tracking query parameters. | 6.20.51 ~ 8.05.51 |
|
| `Sanitize sharing links` | Adds an option to sanitize sharing links by removing tracking query parameters. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Settings for YouTube Music` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 6.20.51 ~ 8.05.51 |
|
| `Settings for YouTube Music` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 6.20.51 ~ 8.10.51 |
|
||||||
| `SponsorBlock` | Adds options to enable and configure SponsorBlock, which can skip undesired video segments, such as non-music sections. | 6.20.51 ~ 8.05.51 |
|
| `SponsorBlock` | Adds options to enable and configure SponsorBlock, which can skip undesired video segments, such as non-music sections. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Spoof app version` | Adds options to spoof the YouTube Music client version. This can be used to restore old UI elements and features. | 6.51.53 ~ 7.16.53 |
|
| `Spoof app version` | Adds options to spoof the YouTube Music client version. This can be used to restore old UI elements and features. | 6.51.53 ~ 7.16.53 |
|
||||||
| `Spoof client` | Adds options to spoof the client to allow playback. | 6.20.51 ~ 8.05.51 |
|
| `Spoof client` | Adds options to spoof the client to allow playback. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Translations for YouTube Music` | Add translations or remove string resources. | 6.20.51 ~ 8.05.51 |
|
| `Spoof player parameter` | Adds options to spoof player parameter to allow playback. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 6.20.51 ~ 8.05.51 |
|
| `Translations for YouTube Music` | Add translations or remove string resources. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Visual preferences icons for YouTube Music` | Adds icons to specific preferences in the settings. | 6.20.51 ~ 8.05.51 |
|
| `Video playback` | Adds options to customize settings related to video playback, such as default video quality and playback speed. | 6.20.51 ~ 8.10.51 |
|
||||||
| `Watch history` | Adds an option to change the domain of the watch history or check its status. | 6.20.51 ~ 8.05.51 |
|
| `Visual preferences icons for YouTube Music` | Adds icons to specific preferences in the settings. | 6.20.51 ~ 8.10.51 |
|
||||||
|
| `Watch history` | Adds an option to change the domain of the watch history or check its status. | 6.20.51 ~ 8.10.51 |
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage)
|
### [📦 `com.reddit.frontpage`](https://play.google.com/store/apps/details?id=com.reddit.frontpage)
|
||||||
@ -187,7 +188,8 @@ Example:
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
|
@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import app.revanced.extension.music.settings.Settings;
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
import app.revanced.extension.music.utils.ExtendedUtils;
|
||||||
import app.revanced.extension.shared.utils.Logger;
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
import app.revanced.extension.shared.utils.ResourceUtils;
|
import app.revanced.extension.shared.utils.ResourceUtils;
|
||||||
|
|
||||||
@ -40,27 +41,17 @@ public final class ChangeStartPagePatch {
|
|||||||
/**
|
/**
|
||||||
* Intent extra.
|
* Intent extra.
|
||||||
*/
|
*/
|
||||||
SEARCH("", 1, "Eh4IBRDTnQEYmgMiEwiZn+H0r5WLAxVV5OcDHcHRBmPqpd25AQA=");
|
SEARCH("");
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
final String browseId;
|
final String browseId;
|
||||||
|
|
||||||
final int shortcutType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unique identifier for shortcut (Base64).
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
final String shortcutId;
|
|
||||||
|
|
||||||
StartPage(@NonNull String browseId) {
|
StartPage(@NonNull String browseId) {
|
||||||
this(browseId, 0, "");
|
this.browseId = browseId;
|
||||||
}
|
}
|
||||||
|
|
||||||
StartPage(@NonNull String browseId, int shortcutType, @NonNull String shortcutId) {
|
public final String getBrowseId() {
|
||||||
this.browseId = browseId;
|
return this.browseId;
|
||||||
this.shortcutType = shortcutType;
|
|
||||||
this.shortcutId = shortcutId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,12 +60,6 @@ public final class ChangeStartPagePatch {
|
|||||||
*/
|
*/
|
||||||
private static final String ACTION_MAIN = "android.intent.action.MAIN";
|
private static final String ACTION_MAIN = "android.intent.action.MAIN";
|
||||||
|
|
||||||
private static final String SHORTCUT_ACTION = "com.google.android.youtube.music.action.shortcut";
|
|
||||||
|
|
||||||
private static final String SHORTCUT_CLASS_DESCRIPTOR = "com.google.android.apps.youtube.music.activities.InternalMusicActivity";
|
|
||||||
|
|
||||||
private static final String SHORTCUT_TYPE = "com.google.android.youtube.music.action.shortcut_type";
|
|
||||||
|
|
||||||
private static final StartPage START_PAGE = Settings.CHANGE_START_PAGE.get();
|
private static final StartPage START_PAGE = Settings.CHANGE_START_PAGE.get();
|
||||||
|
|
||||||
public static String overrideBrowseId(@NonNull String browseId) {
|
public static String overrideBrowseId(@NonNull String browseId) {
|
||||||
@ -96,20 +81,13 @@ public final class ChangeStartPagePatch {
|
|||||||
" as the current activity is not the entry point of the application");
|
" as the current activity is not the entry point of the application");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final String overrideShortcutId = START_PAGE.shortcutId;
|
if (START_PAGE != StartPage.SEARCH) {
|
||||||
if (overrideShortcutId.isEmpty()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Activity mActivity = ResourceUtils.getActivity();
|
Activity mActivity = ResourceUtils.getActivity();
|
||||||
if (mActivity == null) {
|
if (mActivity != null) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Logger.printDebug(() -> "Changing intent action to " + START_PAGE.name());
|
Logger.printDebug(() -> "Changing intent action to " + START_PAGE.name());
|
||||||
intent.setAction(SHORTCUT_ACTION);
|
ExtendedUtils.setSearchIntent(mActivity, intent);
|
||||||
intent.setClassName(mActivity, SHORTCUT_CLASS_DESCRIPTOR);
|
}
|
||||||
intent.setPackage(mActivity.getPackageName());
|
|
||||||
intent.putExtra(SHORTCUT_TYPE, START_PAGE.shortcutType);
|
|
||||||
intent.putExtra(SHORTCUT_ACTION, overrideShortcutId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ public class AlbumMusicVideoPatch {
|
|||||||
VideoUtils.openInYouTubeMusic(songId);
|
VideoUtils.openInYouTubeMusic(songId);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
VideoUtils.runOnMainThreadDelayed(() -> isVideoLaunched.compareAndSet(true, false), 1500);
|
VideoUtils.runOnMainThreadDelayed(() -> isVideoLaunched.compareAndSet(true, false), 2500);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "openMusic failure", ex);
|
Logger.printException(() -> "openMusic failure", ex);
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@ import app.revanced.extension.music.settings.Settings;
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DrcAudioPatch {
|
public class DrcAudioPatch {
|
||||||
|
private static final boolean DISABLE_DRC_AUDIO = Settings.DISABLE_DRC_AUDIO.get();
|
||||||
|
|
||||||
public static float disableDrcAudio(float original) {
|
public static float disableDrcAudio(float original) {
|
||||||
if (!Settings.DISABLE_DRC_AUDIO.get()) {
|
if (DISABLE_DRC_AUDIO) {
|
||||||
return original;
|
|
||||||
}
|
|
||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
return original;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,174 @@
|
|||||||
|
package app.revanced.extension.music.patches.misc;
|
||||||
|
|
||||||
|
import static app.revanced.extension.music.shared.VideoInformation.parameterIsAgeRestricted;
|
||||||
|
import static app.revanced.extension.music.shared.VideoInformation.parameterIsSample;
|
||||||
|
|
||||||
|
import androidx.annotation.GuardedBy;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
import app.revanced.extension.music.shared.VideoInformation;
|
||||||
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class SpoofPlayerParameterPatch {
|
||||||
|
/**
|
||||||
|
* Used in YouTube Music.
|
||||||
|
*/
|
||||||
|
private static final boolean SPOOF_PLAYER_PARAMETER = Settings.SPOOF_PLAYER_PARAMETER.get();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter to fix playback issues.
|
||||||
|
* Used in YouTube Music Samples.
|
||||||
|
*/
|
||||||
|
private static final String PLAYER_PARAMETER_SAMPLES =
|
||||||
|
"8AEB2AUBogYVAUY4C8W9wrM-FdhjSW4MnCgH44uhkAcI";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parameter to fix playback issues.
|
||||||
|
* Used in YouTube Shorts.
|
||||||
|
*/
|
||||||
|
private static final String PLAYER_PARAMETER_SHORTS =
|
||||||
|
"8AEByAMkuAQ0ogYVAePzwRN3uesV1sPI2x4-GkDYlvqUkAcC";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* On app first start, the first video played usually contains a single non-default window setting value
|
||||||
|
* and all other subtitle settings for the video are (incorrect) default Samples window settings.
|
||||||
|
* For this situation, the Samples settings must be replaced.
|
||||||
|
* <p>
|
||||||
|
* But some videos use multiple text positions on screen (such as youtu.be/3hW1rMNC89o),
|
||||||
|
* and by chance many of the subtitles uses window positions that match a default Samples position.
|
||||||
|
* To handle these videos, selectively allowing the Samples specific window settings to 'pass thru' unchanged,
|
||||||
|
* but only if the video contains multiple non-default subtitle window positions.
|
||||||
|
* <p>
|
||||||
|
* Do not enable 'pass thru mode' until this many non default subtitle settings are observed for a single video.
|
||||||
|
*/
|
||||||
|
private static final int NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU = 2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of non default subtitle settings encountered for the current video.
|
||||||
|
*/
|
||||||
|
private static int numberOfNonDefaultSettingsObserved;
|
||||||
|
|
||||||
|
@GuardedBy("itself")
|
||||||
|
private static final Map<String, Boolean> lastVideoIds = new LinkedHashMap<>() {
|
||||||
|
private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 5;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean removeEldestEntry(Entry eldest) {
|
||||||
|
return size() > NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static String spoofParameter(@NonNull String videoId, @Nullable String parameter) {
|
||||||
|
if (SPOOF_PLAYER_PARAMETER) {
|
||||||
|
synchronized (lastVideoIds) {
|
||||||
|
Boolean isSamples = parameterIsSample(parameter);
|
||||||
|
if (lastVideoIds.put(videoId, isSamples) == null) {
|
||||||
|
Logger.printDebug(() -> "New video loaded (videoId: " + videoId + ", isSamples: " + isSamples + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return parameterIsAgeRestricted(parameter)
|
||||||
|
? PLAYER_PARAMETER_SHORTS
|
||||||
|
: PLAYER_PARAMETER_SAMPLES;
|
||||||
|
}
|
||||||
|
return parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point. Overrides values passed into SubtitleWindowSettings constructor.
|
||||||
|
*
|
||||||
|
* @param ap anchor position. A bitmask with 6 bit fields, that appears to indicate the layout position on screen
|
||||||
|
* @param ah anchor horizontal. A percentage [0, 100], that appears to be a horizontal text anchor point
|
||||||
|
* @param av anchor vertical. A percentage [0, 100], that appears to be a vertical text anchor point
|
||||||
|
* @param vs appears to indicate if subtitles exist, and the value is always true.
|
||||||
|
* @param sd function is not entirely clear
|
||||||
|
*/
|
||||||
|
public static int[] fixSubtitleWindowPosition(int ap, int ah, int av, boolean vs, boolean sd) {
|
||||||
|
// Videos with custom captions that specify screen positions appear to always have correct screen positions (even with spoofing).
|
||||||
|
// But for auto generated and most other captions, the spoof incorrectly gives various default Samples caption settings.
|
||||||
|
// Check for these known default Samples captions parameters, and replace with the known correct values.
|
||||||
|
//
|
||||||
|
// If a regular video uses a custom subtitle setting that match a default Samples setting,
|
||||||
|
// then this will incorrectly replace the setting.
|
||||||
|
// But, if the video uses multiple subtitles in different screen locations, then detect the non-default values
|
||||||
|
// and do not replace any window settings for the video (regardless if they match a Samples default).
|
||||||
|
if (SPOOF_PLAYER_PARAMETER &&
|
||||||
|
numberOfNonDefaultSettingsObserved < NUMBER_OF_NON_DEFAULT_SUBTITLES_BEFORE_ENABLING_PASSTHRU) {
|
||||||
|
synchronized (lastVideoIds) {
|
||||||
|
String videoId = VideoInformation.getVideoId();
|
||||||
|
Boolean isSample = lastVideoIds.get(videoId);
|
||||||
|
if (BooleanUtils.isFalse(isSample)) {
|
||||||
|
for (SubtitleWindowReplacementSettings setting : SubtitleWindowReplacementSettings.values()) {
|
||||||
|
if (setting.match(ap, ah, av, vs, sd)) {
|
||||||
|
return setting.replacementSetting();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
numberOfNonDefaultSettingsObserved++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new int[]{ap, ah, av};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
* <p>
|
||||||
|
* Return false to force disable age restricted playback feature flag.
|
||||||
|
*/
|
||||||
|
public static boolean forceDisableAgeRestrictedPlaybackFeatureFlag(boolean original) {
|
||||||
|
if (SPOOF_PLAYER_PARAMETER) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Known incorrect default Samples subtitle parameters, and the corresponding correct (non-Samples) values.
|
||||||
|
*/
|
||||||
|
private enum SubtitleWindowReplacementSettings {
|
||||||
|
DEFAULT_SAMPLES_PARAMETERS_1(10, 50, 0, true, false,
|
||||||
|
34, 50, 95),
|
||||||
|
DEFAULT_SAMPLES_PARAMETERS_2(9, 20, 0, true, false,
|
||||||
|
34, 50, 90),
|
||||||
|
DEFAULT_SAMPLES_PARAMETERS_3(9, 20, 0, true, true,
|
||||||
|
33, 20, 100);
|
||||||
|
|
||||||
|
// original values
|
||||||
|
final int ap, ah, av;
|
||||||
|
final boolean vs, sd;
|
||||||
|
|
||||||
|
// replacement int values
|
||||||
|
final int[] replacement;
|
||||||
|
|
||||||
|
SubtitleWindowReplacementSettings(int ap, int ah, int av, boolean vs, boolean sd,
|
||||||
|
int replacementAp, int replacementAh, int replacementAv) {
|
||||||
|
this.ap = ap;
|
||||||
|
this.ah = ah;
|
||||||
|
this.av = av;
|
||||||
|
this.vs = vs;
|
||||||
|
this.sd = sd;
|
||||||
|
this.replacement = new int[]{replacementAp, replacementAh, replacementAv};
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean match(int ap, int ah, int av, boolean vs, boolean sd) {
|
||||||
|
return this.ap == ap && this.ah == ah && this.av == av && this.vs == vs && this.sd == sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] replacementSetting() {
|
||||||
|
return replacement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ import androidx.annotation.GuardedBy
|
|||||||
import app.revanced.extension.shared.patches.client.YouTubeAppClient
|
import app.revanced.extension.shared.patches.client.YouTubeAppClient
|
||||||
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes
|
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes
|
||||||
import app.revanced.extension.shared.requests.Requester
|
import app.revanced.extension.shared.requests.Requester
|
||||||
|
import app.revanced.extension.shared.settings.AppLanguage
|
||||||
import app.revanced.extension.shared.utils.Logger
|
import app.revanced.extension.shared.utils.Logger
|
||||||
import app.revanced.extension.shared.utils.Utils
|
import app.revanced.extension.shared.utils.Utils
|
||||||
import org.json.JSONException
|
import org.json.JSONException
|
||||||
@ -139,11 +140,24 @@ class PlaylistRequest private constructor(
|
|||||||
PlayerRoutes.GET_PLAYLIST_PAGE,
|
PlayerRoutes.GET_PLAYLIST_PAGE,
|
||||||
clientType
|
clientType
|
||||||
)
|
)
|
||||||
|
/**
|
||||||
|
* For some reason, the tracks in Top Songs have the playlistId of the album:
|
||||||
|
* [ReVanced_Extended#2835](https://github.com/inotia00/ReVanced_Extended/issues/2835)
|
||||||
|
*
|
||||||
|
* We can work around this issue by checking the playlist title in the response.
|
||||||
|
* Tracks played from an album have a playlist title that starts with 'Album',
|
||||||
|
* Tracks played from Top Songs have a playlist title that starts with 'Song'.
|
||||||
|
*
|
||||||
|
* By default, the playlist title follows the app language,
|
||||||
|
* So we can work around this by setting the language to English when sending the request.
|
||||||
|
*/
|
||||||
val requestBody =
|
val requestBody =
|
||||||
PlayerRoutes.createApplicationRequestBody(
|
PlayerRoutes.createApplicationRequestBody(
|
||||||
clientType = clientType,
|
clientType = clientType,
|
||||||
videoId = videoId,
|
videoId = videoId,
|
||||||
playlistId = playlistId
|
playlistId = playlistId,
|
||||||
|
setLocale = true,
|
||||||
|
language = AppLanguage.EN.language,
|
||||||
)
|
)
|
||||||
|
|
||||||
connection.setFixedLengthStreamingMode(requestBody.size)
|
connection.setFixedLengthStreamingMode(requestBody.size)
|
||||||
@ -183,6 +197,10 @@ class PlaylistRequest private constructor(
|
|||||||
.getJSONObject("playlist")
|
.getJSONObject("playlist")
|
||||||
.getJSONObject("playlist")
|
.getJSONObject("playlist")
|
||||||
|
|
||||||
|
val playlistTitle = playlistJsonObject
|
||||||
|
?.getString("title") + ""
|
||||||
|
|
||||||
|
if (playlistTitle.startsWith("Album")) {
|
||||||
val currentStreamJsonObject = playlistJsonObject
|
val currentStreamJsonObject = playlistJsonObject
|
||||||
?.getJSONArray("contents")
|
?.getJSONArray("contents")
|
||||||
?.get(playlistIndex)
|
?.get(playlistIndex)
|
||||||
@ -197,6 +215,7 @@ class PlaylistRequest private constructor(
|
|||||||
return watchEndpointJsonObject?.getString("videoId") + ""
|
return watchEndpointJsonObject?.getString("videoId") + ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch (e: JSONException) {
|
} catch (e: JSONException) {
|
||||||
Logger.printException(
|
Logger.printException(
|
||||||
{ "Fetch failed while processing response data for response: $playlistJson" },
|
{ "Fetch failed while processing response data for response: $playlistJson" },
|
||||||
|
@ -4,13 +4,19 @@ import static app.revanced.extension.shared.utils.StringRef.str;
|
|||||||
import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition;
|
import static app.revanced.extension.shared.utils.Utils.hideViewUnderCondition;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import app.revanced.extension.music.patches.utils.PatchStatus;
|
import app.revanced.extension.music.patches.utils.PatchStatus;
|
||||||
import app.revanced.extension.music.settings.Settings;
|
import app.revanced.extension.music.settings.Settings;
|
||||||
|
import app.revanced.extension.music.utils.ExtendedUtils;
|
||||||
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
import app.revanced.extension.shared.utils.ResourceUtils;
|
import app.revanced.extension.shared.utils.ResourceUtils;
|
||||||
import app.revanced.extension.shared.utils.Utils;
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
|
||||||
@ -20,7 +26,14 @@ public class NavigationPatch {
|
|||||||
? ResourceUtils.getColor("ytm_color_grey_12")
|
? ResourceUtils.getColor("ytm_color_grey_12")
|
||||||
: ResourceUtils.getColor("revanced_color_grey_12");
|
: ResourceUtils.getColor("revanced_color_grey_12");
|
||||||
|
|
||||||
public static Enum<?> lastPivotTab;
|
@Nullable
|
||||||
|
private static String lastYTNavigationEnumName;
|
||||||
|
|
||||||
|
public static void setLastAppNavigationEnum(@Nullable Enum<?> ytNavigationEnumName) {
|
||||||
|
if (ytNavigationEnumName != null) {
|
||||||
|
lastYTNavigationEnumName = ytNavigationEnumName.name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static int enableCustomNavigationBarColor() {
|
public static int enableCustomNavigationBarColor() {
|
||||||
try {
|
try {
|
||||||
@ -46,24 +59,138 @@ public class NavigationPatch {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (NavigationButton button : NavigationButton.values())
|
for (NavigationButton button : NavigationButton.values()) {
|
||||||
if (lastPivotTab.name().equals(button.name))
|
if (button.ytEnumNames.equals(lastYTNavigationEnumName)) {
|
||||||
hideViewUnderCondition(button.enabled, view);
|
if (button.replace) {
|
||||||
|
Runnable onClickAction = button.onClickAction;
|
||||||
|
if (onClickAction != null) {
|
||||||
|
view.setOnClickListener(v -> onClickAction.run());
|
||||||
|
Utils.runOnMainThreadDelayed(() -> view.setOnClickListener(v -> onClickAction.run()), 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hideViewUnderCondition(button.hidden, view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String replaceBrowseId(Object component, String browseId, String fieldName) {
|
||||||
|
for (NavigationButton button : NavigationButton.values()) {
|
||||||
|
if (button.replace && button.browseId.equals(browseId)) {
|
||||||
|
String replaceBrowseId = Settings.CHANGE_START_PAGE.get().getBrowseId();
|
||||||
|
if (replaceBrowseId.isEmpty()) {
|
||||||
|
replaceBrowseId = NavigationButton.HOME.browseId;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Field browseIdField = component.getClass().getField(fieldName);
|
||||||
|
browseIdField.setAccessible(true);
|
||||||
|
browseIdField.set(component, replaceBrowseId);
|
||||||
|
return replaceBrowseId;
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
Logger.printException(() -> "replaceBrowseId failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return browseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int replaceNavigationIcon(int drawableId) {
|
||||||
|
for (NavigationButton button : NavigationButton.values()) {
|
||||||
|
if (button.replace &&
|
||||||
|
(drawableId == button.unSelectedDrawableId || drawableId == button.selectedDrawableId)) {
|
||||||
|
int replaceDrawableId = button.replaceDrawableId;
|
||||||
|
if (replaceDrawableId != 0) {
|
||||||
|
return replaceDrawableId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return drawableId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Spanned replaceNavigationLabel(@NonNull Spanned sourceStyle) {
|
||||||
|
for (NavigationButton button : NavigationButton.values()) {
|
||||||
|
if (button.ytEnumNames.equals(lastYTNavigationEnumName) && button.replace) {
|
||||||
|
String label = button.label;
|
||||||
|
if (!label.isEmpty()) {
|
||||||
|
return Utils.newSpanUsingStylingOfAnotherSpan(sourceStyle, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum NavigationButton {
|
private enum NavigationButton {
|
||||||
HOME("TAB_HOME", Settings.HIDE_NAVIGATION_HOME_BUTTON.get()),
|
HOME(
|
||||||
SAMPLES("TAB_SAMPLES", Settings.HIDE_NAVIGATION_SAMPLES_BUTTON.get()),
|
"TAB_HOME",
|
||||||
EXPLORE("TAB_EXPLORE", Settings.HIDE_NAVIGATION_EXPLORE_BUTTON.get()),
|
Settings.HIDE_NAVIGATION_HOME_BUTTON.get(),
|
||||||
LIBRARY("LIBRARY_MUSIC", Settings.HIDE_NAVIGATION_LIBRARY_BUTTON.get()),
|
"FEmusic_home"
|
||||||
UPGRADE("TAB_MUSIC_PREMIUM", Settings.HIDE_NAVIGATION_UPGRADE_BUTTON.get());
|
),
|
||||||
|
SAMPLES(
|
||||||
|
"TAB_SAMPLES",
|
||||||
|
Settings.HIDE_NAVIGATION_SAMPLES_BUTTON.get(),
|
||||||
|
Settings.REPLACE_NAVIGATION_SAMPLES_BUTTON.get(),
|
||||||
|
"FEmusic_immersive",
|
||||||
|
"search",
|
||||||
|
"yt_fill_samples_vd_theme_24",
|
||||||
|
"yt_outline_samples_vd_theme_24",
|
||||||
|
"yt_outline_search_vd_theme_24",
|
||||||
|
ExtendedUtils::openSearch
|
||||||
|
),
|
||||||
|
EXPLORE(
|
||||||
|
"TAB_EXPLORE",
|
||||||
|
Settings.HIDE_NAVIGATION_EXPLORE_BUTTON.get(),
|
||||||
|
"FEmusic_explore"
|
||||||
|
),
|
||||||
|
LIBRARY(
|
||||||
|
"LIBRARY_MUSIC",
|
||||||
|
Settings.HIDE_NAVIGATION_LIBRARY_BUTTON.get(),
|
||||||
|
"FEmusic_library_landing"
|
||||||
|
),
|
||||||
|
UPGRADE(
|
||||||
|
"TAB_MUSIC_PREMIUM",
|
||||||
|
Settings.HIDE_NAVIGATION_UPGRADE_BUTTON.get(),
|
||||||
|
Settings.REPLACE_NAVIGATION_UPGRADE_BUTTON.get(),
|
||||||
|
"SPunlimited",
|
||||||
|
"settings",
|
||||||
|
"yt_fill_youtube_music_vd_theme_24",
|
||||||
|
"yt_outline_youtube_music_vd_theme_24",
|
||||||
|
"yt_outline_gear_vd_theme_24",
|
||||||
|
ExtendedUtils::openSetting
|
||||||
|
);
|
||||||
|
|
||||||
private final boolean enabled;
|
private final String ytEnumNames;
|
||||||
private final String name;
|
private final boolean hidden;
|
||||||
|
private final boolean replace;
|
||||||
|
@NonNull
|
||||||
|
private final String browseId;
|
||||||
|
@NonNull
|
||||||
|
private final String label;
|
||||||
|
private final int selectedDrawableId;
|
||||||
|
private final int unSelectedDrawableId;
|
||||||
|
private final int replaceDrawableId;
|
||||||
|
@Nullable
|
||||||
|
private final Runnable onClickAction;
|
||||||
|
|
||||||
NavigationButton(String name, boolean enabled) {
|
NavigationButton(@NonNull String ytEnumNames, boolean hidden,
|
||||||
this.enabled = enabled;
|
@NonNull String browseId) {
|
||||||
this.name = name;
|
this(ytEnumNames, hidden, false, browseId, null, null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationButton(@NonNull String ytEnumNames, boolean hidden, boolean replace,
|
||||||
|
@NonNull String browseId, @Nullable String label,
|
||||||
|
@Nullable String selectedIcon, @Nullable String unSelectedIcon,
|
||||||
|
@Nullable String replaceIcon, @Nullable Runnable onClickAction) {
|
||||||
|
this.ytEnumNames = ytEnumNames;
|
||||||
|
this.hidden = hidden;
|
||||||
|
this.replace = replace;
|
||||||
|
this.browseId = browseId;
|
||||||
|
this.label = label != null ? ResourceUtils.getString(label) : "";
|
||||||
|
this.selectedDrawableId = selectedIcon != null ? ResourceUtils.getDrawableIdentifier(selectedIcon) : 0;
|
||||||
|
this.unSelectedDrawableId = unSelectedIcon != null ? ResourceUtils.getDrawableIdentifier(unSelectedIcon) : 0;
|
||||||
|
this.replaceDrawableId = replaceIcon != null ? ResourceUtils.getDrawableIdentifier(replaceIcon) : 0;
|
||||||
|
this.onClickAction = onClickAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package app.revanced.extension.music.returnyoutubedislike;
|
|||||||
import static app.revanced.extension.shared.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
import static app.revanced.extension.shared.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
||||||
import static app.revanced.extension.shared.utils.StringRef.str;
|
import static app.revanced.extension.shared.utils.StringRef.str;
|
||||||
import static app.revanced.extension.shared.utils.Utils.isSDKAbove;
|
import static app.revanced.extension.shared.utils.Utils.isSDKAbove;
|
||||||
|
import static app.revanced.extension.shared.utils.Utils.newSpanUsingStylingOfAnotherSpan;
|
||||||
|
|
||||||
import android.graphics.Canvas;
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
@ -283,15 +284,6 @@ public class ReturnYouTubeDislike {
|
|||||||
: formatDislikeCount(voteData.getDislikeCount()));
|
: formatDislikeCount(voteData.getDislikeCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SpannableString newSpanUsingStylingOfAnotherSpan(@NonNull Spanned sourceStyle, @NonNull CharSequence newSpanText) {
|
|
||||||
SpannableString destination = new SpannableString(newSpanText);
|
|
||||||
Object[] spans = sourceStyle.getSpans(0, sourceStyle.length(), Object.class);
|
|
||||||
for (Object span : spans) {
|
|
||||||
destination.setSpan(span, 0, destination.length(), sourceStyle.getSpanFlags(span));
|
|
||||||
}
|
|
||||||
return destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String formatDislikeCount(long dislikeCount) {
|
private static String formatDislikeCount(long dislikeCount) {
|
||||||
if (isSDKAbove(24)) {
|
if (isSDKAbove(24)) {
|
||||||
if (dislikeCountFormatter == null) {
|
if (dislikeCountFormatter == null) {
|
||||||
|
@ -130,6 +130,9 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting HIDE_NAVIGATION_UPGRADE_BUTTON = new BooleanSetting("revanced_hide_navigation_upgrade_button", TRUE, true);
|
public static final BooleanSetting HIDE_NAVIGATION_UPGRADE_BUTTON = new BooleanSetting("revanced_hide_navigation_upgrade_button", TRUE, true);
|
||||||
public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_hide_navigation_bar", FALSE, true);
|
public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_hide_navigation_bar", FALSE, true);
|
||||||
public static final BooleanSetting HIDE_NAVIGATION_LABEL = new BooleanSetting("revanced_hide_navigation_label", FALSE, true);
|
public static final BooleanSetting HIDE_NAVIGATION_LABEL = new BooleanSetting("revanced_hide_navigation_label", FALSE, true);
|
||||||
|
public static final BooleanSetting REPLACE_NAVIGATION_SAMPLES_BUTTON = new BooleanSetting("revanced_replace_navigation_samples_button", FALSE, true);
|
||||||
|
public static final BooleanSetting REPLACE_NAVIGATION_UPGRADE_BUTTON = new BooleanSetting("revanced_replace_navigation_upgrade_button", FALSE, true);
|
||||||
|
public static final BooleanSetting REPLACE_NAVIGATION_BUTTON_ABOUT = new BooleanSetting("revanced_replace_navigation_button_about", FALSE, false);
|
||||||
|
|
||||||
|
|
||||||
// PreferenceScreen: Player
|
// PreferenceScreen: Player
|
||||||
@ -190,6 +193,7 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting DISABLE_DRC_AUDIO = new BooleanSetting("revanced_disable_drc_audio", FALSE, true);
|
public static final BooleanSetting DISABLE_DRC_AUDIO = new BooleanSetting("revanced_disable_drc_audio", FALSE, true);
|
||||||
public static final BooleanSetting DISABLE_MUSIC_VIDEO_IN_ALBUM = new BooleanSetting("revanced_disable_music_video_in_album", FALSE, true);
|
public static final BooleanSetting DISABLE_MUSIC_VIDEO_IN_ALBUM = new BooleanSetting("revanced_disable_music_video_in_album", FALSE, true);
|
||||||
public static final EnumSetting<RedirectType> DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE = new EnumSetting<>("revanced_disable_music_video_in_album_redirect_type", RedirectType.REDIRECT, true);
|
public static final EnumSetting<RedirectType> DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE = new EnumSetting<>("revanced_disable_music_video_in_album_redirect_type", RedirectType.REDIRECT, true);
|
||||||
|
public static final BooleanSetting SPOOF_PLAYER_PARAMETER = new BooleanSetting("revanced_spoof_player_parameter", TRUE, true);
|
||||||
public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false);
|
public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false);
|
||||||
|
|
||||||
// PreferenceScreen: Return YouTube Dislike
|
// PreferenceScreen: Return YouTube Dislike
|
||||||
@ -276,6 +280,7 @@ public class Settings extends BaseSettings {
|
|||||||
RETURN_YOUTUBE_USERNAME_ABOUT.key,
|
RETURN_YOUTUBE_USERNAME_ABOUT.key,
|
||||||
RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT.key,
|
RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT.key,
|
||||||
RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY.key,
|
RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY.key,
|
||||||
|
REPLACE_NAVIGATION_BUTTON_ABOUT.key,
|
||||||
SB_API_URL.key,
|
SB_API_URL.key,
|
||||||
SETTINGS_IMPORT_EXPORT.key,
|
SETTINGS_IMPORT_EXPORT.key,
|
||||||
SPOOF_APP_VERSION_TARGET.key,
|
SPOOF_APP_VERSION_TARGET.key,
|
||||||
|
@ -12,6 +12,7 @@ import static app.revanced.extension.music.settings.Settings.EXTERNAL_DOWNLOADER
|
|||||||
import static app.revanced.extension.music.settings.Settings.HIDE_ACCOUNT_MENU_FILTER_STRINGS;
|
import static app.revanced.extension.music.settings.Settings.HIDE_ACCOUNT_MENU_FILTER_STRINGS;
|
||||||
import static app.revanced.extension.music.settings.Settings.OPEN_DEFAULT_APP_SETTINGS;
|
import static app.revanced.extension.music.settings.Settings.OPEN_DEFAULT_APP_SETTINGS;
|
||||||
import static app.revanced.extension.music.settings.Settings.OPTIONAL_SPONSOR_BLOCK_SETTINGS_PREFIX;
|
import static app.revanced.extension.music.settings.Settings.OPTIONAL_SPONSOR_BLOCK_SETTINGS_PREFIX;
|
||||||
|
import static app.revanced.extension.music.settings.Settings.REPLACE_NAVIGATION_BUTTON_ABOUT;
|
||||||
import static app.revanced.extension.music.settings.Settings.RETURN_YOUTUBE_USERNAME_ABOUT;
|
import static app.revanced.extension.music.settings.Settings.RETURN_YOUTUBE_USERNAME_ABOUT;
|
||||||
import static app.revanced.extension.music.settings.Settings.SB_API_URL;
|
import static app.revanced.extension.music.settings.Settings.SB_API_URL;
|
||||||
import static app.revanced.extension.music.settings.Settings.SETTINGS_IMPORT_EXPORT;
|
import static app.revanced.extension.music.settings.Settings.SETTINGS_IMPORT_EXPORT;
|
||||||
@ -161,6 +162,8 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
|
|||||||
importExportListDialogBuilder();
|
importExportListDialogBuilder();
|
||||||
} else if (settings.equals(RETURN_YOUTUBE_USERNAME_ABOUT)) {
|
} else if (settings.equals(RETURN_YOUTUBE_USERNAME_ABOUT)) {
|
||||||
YouTubeDataAPIDialogBuilder.showDialog(mActivity);
|
YouTubeDataAPIDialogBuilder.showDialog(mActivity);
|
||||||
|
} else if (settings.equals(REPLACE_NAVIGATION_BUTTON_ABOUT)) {
|
||||||
|
ResettableListPreference.showDialog(mActivity, CHANGE_START_PAGE, 0);
|
||||||
} else {
|
} else {
|
||||||
Logger.printDebug(() -> "Failed to find the right value: " + dataString);
|
Logger.printDebug(() -> "Failed to find the right value: " + dataString);
|
||||||
}
|
}
|
||||||
|
@ -22,12 +22,25 @@ public final class VideoInformation {
|
|||||||
private static final float DEFAULT_YOUTUBE_MUSIC_PLAYBACK_SPEED = 1.0f;
|
private static final float DEFAULT_YOUTUBE_MUSIC_PLAYBACK_SPEED = 1.0f;
|
||||||
private static final int DEFAULT_YOUTUBE_MUSIC_VIDEO_QUALITY = -2;
|
private static final int DEFAULT_YOUTUBE_MUSIC_VIDEO_QUALITY = -2;
|
||||||
private static final String DEFAULT_YOUTUBE_MUSIC_VIDEO_QUALITY_STRING = getString("quality_auto");
|
private static final String DEFAULT_YOUTUBE_MUSIC_VIDEO_QUALITY_STRING = getString("quality_auto");
|
||||||
|
/**
|
||||||
|
* Prefix present in all Age-restricted music player parameters signature.
|
||||||
|
*/
|
||||||
|
private static final String AGE_RESTRICTED_PLAYER_PARAMETER = "ygYQ";
|
||||||
|
/**
|
||||||
|
* Prefix present in all Sample player parameters signature.
|
||||||
|
*/
|
||||||
|
private static final String SAMPLES_PLAYER_PARAMETERS = "8AEB";
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static String videoId = "";
|
private static String videoId = "";
|
||||||
|
|
||||||
private static long videoLength = 0;
|
private static long videoLength = 0;
|
||||||
private static long videoTime = -1;
|
private static long videoTime = -1;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static volatile String playerResponseVideoId = "";
|
||||||
|
private static volatile boolean playerResponseVideoIdIsSample;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The current playback speed
|
* The current playback speed
|
||||||
*/
|
*/
|
||||||
@ -85,6 +98,65 @@ public final class VideoInformation {
|
|||||||
videoId = newlyLoadedVideoId;
|
videoId = newlyLoadedVideoId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Differs from {@link #videoId} as this is the video id for the
|
||||||
|
* last player response received, which may not be the last video opened.
|
||||||
|
* <p>
|
||||||
|
* If Shorts are loading the background, this commonly will be
|
||||||
|
* different from the Short that is currently on screen.
|
||||||
|
* <p>
|
||||||
|
* For most use cases, you should instead use {@link #getVideoId()}.
|
||||||
|
*
|
||||||
|
* @return The id of the last video loaded, or an empty string if no videos have been loaded yet.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String getPlayerResponseVideoId() {
|
||||||
|
return playerResponseVideoId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If the last player response video id was a Sample.
|
||||||
|
*/
|
||||||
|
public static boolean lastPlayerResponseIsSample() {
|
||||||
|
return playerResponseVideoIdIsSample;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point. Called off the main thread.
|
||||||
|
*
|
||||||
|
* @param videoId The id of the last video loaded.
|
||||||
|
*/
|
||||||
|
public static void setPlayerResponseVideoId(@NonNull String videoId) {
|
||||||
|
if (!playerResponseVideoId.equals(videoId)) {
|
||||||
|
playerResponseVideoId = videoId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If the player parameter is for a Age-restricted video.
|
||||||
|
*/
|
||||||
|
public static boolean parameterIsAgeRestricted(@Nullable String parameter) {
|
||||||
|
return parameter != null && parameter.startsWith(AGE_RESTRICTED_PLAYER_PARAMETER);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If the player parameter is for a Sample.
|
||||||
|
*/
|
||||||
|
public static boolean parameterIsSample(@Nullable String parameter) {
|
||||||
|
return parameter != null && parameter.startsWith(SAMPLES_PLAYER_PARAMETERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public static String newPlayerResponseParameter(@NonNull String videoId, @Nullable String playerParameter) {
|
||||||
|
playerResponseVideoIdIsSample = parameterIsSample(playerParameter);
|
||||||
|
Logger.printDebug(() -> "videoId: " + videoId + ", playerParameter: " + playerParameter);
|
||||||
|
|
||||||
|
return playerParameter; // Return the original value since we are observing and not modifying.
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seek on the current video.
|
* Seek on the current video.
|
||||||
* Does not function for playback of Shorts.
|
* Does not function for playback of Shorts.
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
package app.revanced.extension.music.utils;
|
package app.revanced.extension.music.utils;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
@ -9,8 +11,20 @@ import androidx.annotation.NonNull;
|
|||||||
|
|
||||||
import app.revanced.extension.music.settings.Settings;
|
import app.revanced.extension.music.settings.Settings;
|
||||||
import app.revanced.extension.shared.utils.PackageUtils;
|
import app.revanced.extension.shared.utils.PackageUtils;
|
||||||
|
import app.revanced.extension.shared.utils.ResourceUtils;
|
||||||
|
|
||||||
public class ExtendedUtils extends PackageUtils {
|
public class ExtendedUtils extends PackageUtils {
|
||||||
|
private static final String SETTINGS_CLASS_DESCRIPTOR = "com.google.android.apps.youtube.music.settings.SettingsCompatActivity";
|
||||||
|
private static final String SETTINGS_ATTRIBUTION_FRAGMENT_KEY = ":android:show_fragment";
|
||||||
|
private static final String SETTINGS_ATTRIBUTION_FRAGMENT_VALUE = "com.google.android.apps.youtube.music.settings.fragment.SettingsHeadersFragment";
|
||||||
|
private static final String SETTINGS_ATTRIBUTION_HEADER_KEY = ":android:no_headers";
|
||||||
|
private static final int SETTINGS_ATTRIBUTION_HEADER_VALUE = 1;
|
||||||
|
|
||||||
|
private static final String SHORTCUT_ACTION = "com.google.android.youtube.music.action.shortcut";
|
||||||
|
private static final String SHORTCUT_CLASS_DESCRIPTOR = "com.google.android.apps.youtube.music.activities.InternalMusicActivity";
|
||||||
|
private static final String SHORTCUT_TYPE = "com.google.android.youtube.music.action.shortcut_type";
|
||||||
|
private static final String SHORTCUT_ID_SEARCH = "Eh4IBRDTnQEYmgMiEwiZn+H0r5WLAxVV5OcDHcHRBmPqpd25AQA=";
|
||||||
|
private static final int SHORTCUT_TYPE_SEARCH = 1;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public static boolean isSpoofingToLessThan(@NonNull String versionName) {
|
public static boolean isSpoofingToLessThan(@NonNull String versionName) {
|
||||||
@ -39,4 +53,35 @@ public class ExtendedUtils extends PackageUtils {
|
|||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void openSearch() {
|
||||||
|
Activity mActivity = ResourceUtils.getActivity();
|
||||||
|
if (mActivity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent();
|
||||||
|
setSearchIntent(mActivity, intent);
|
||||||
|
mActivity.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openSetting() {
|
||||||
|
Activity mActivity = ResourceUtils.getActivity();
|
||||||
|
if (mActivity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setPackage(mActivity.getPackageName());
|
||||||
|
intent.setClassName(mActivity, SETTINGS_CLASS_DESCRIPTOR);
|
||||||
|
intent.putExtra(SETTINGS_ATTRIBUTION_FRAGMENT_KEY, SETTINGS_ATTRIBUTION_FRAGMENT_VALUE);
|
||||||
|
intent.putExtra(SETTINGS_ATTRIBUTION_HEADER_KEY, SETTINGS_ATTRIBUTION_HEADER_VALUE);
|
||||||
|
mActivity.startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setSearchIntent(Activity mActivity, Intent intent) {
|
||||||
|
intent.setAction(SHORTCUT_ACTION);
|
||||||
|
intent.setClassName(mActivity, SHORTCUT_CLASS_DESCRIPTOR);
|
||||||
|
intent.setPackage(mActivity.getPackageName());
|
||||||
|
intent.putExtra(SHORTCUT_TYPE, SHORTCUT_TYPE_SEARCH);
|
||||||
|
intent.putExtra(SHORTCUT_ACTION, SHORTCUT_ID_SEARCH);
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,8 +3,7 @@ package app.revanced.extension.shared.patches;
|
|||||||
import static java.lang.Boolean.FALSE;
|
import static java.lang.Boolean.FALSE;
|
||||||
import static java.lang.Boolean.TRUE;
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
import android.text.SpannableString;
|
import static app.revanced.extension.shared.utils.Utils.newSpanUsingStylingOfAnotherSpan;
|
||||||
import android.text.Spanned;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
@ -73,26 +72,13 @@ public class ReturnYouTubeUsernamePatch {
|
|||||||
Logger.printDebug(() -> "ChannelRequest Stream is null, handle:" + handle);
|
Logger.printDebug(() -> "ChannelRequest Stream is null, handle:" + handle);
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
return copySpannableString(original, userName);
|
return newSpanUsingStylingOfAnotherSpan(original, userName);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "onLithoTextLoaded failure", ex);
|
Logger.printException(() -> "onLithoTextLoaded failure", ex);
|
||||||
}
|
}
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static CharSequence copySpannableString(CharSequence original, String userName) {
|
|
||||||
if (original instanceof Spanned spanned) {
|
|
||||||
SpannableString newString = new SpannableString(userName);
|
|
||||||
Object[] spans = spanned.getSpans(0, spanned.length(), Object.class);
|
|
||||||
for (Object span : spans) {
|
|
||||||
int flags = spanned.getSpanFlags(span);
|
|
||||||
newString.setSpan(span, 0, newString.length(), flags);
|
|
||||||
}
|
|
||||||
return newString;
|
|
||||||
}
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum DisplayFormat {
|
public enum DisplayFormat {
|
||||||
USERNAME_ONLY(null),
|
USERNAME_ONLY(null),
|
||||||
USERNAME_HANDLE(TRUE),
|
USERNAME_HANDLE(TRUE),
|
||||||
|
@ -27,28 +27,28 @@ object YouTubeAppClient {
|
|||||||
private val CLIENT_VERSION_IOS = if (forceAVC())
|
private val CLIENT_VERSION_IOS = if (forceAVC())
|
||||||
"17.40.5"
|
"17.40.5"
|
||||||
else
|
else
|
||||||
"19.29.1"
|
"20.10.4"
|
||||||
|
|
||||||
private const val DEVICE_MAKE_IOS = "Apple"
|
private const val DEVICE_MAKE_IOS = "Apple"
|
||||||
private const val OS_NAME_IOS = "iOS"
|
private const val OS_NAME_IOS = "iOS"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The device machine id for the iPhone 15 Pro Max (iPhone16,2),
|
* The device machine id for the iPhone 16 Pro Max (iPhone17,2),
|
||||||
* used to get HDR with AV1 hardware decoding.
|
* used to get HDR with AV1 hardware decoding.
|
||||||
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
|
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
|
||||||
*/
|
*/
|
||||||
private val DEVICE_MODEL_IOS = if (forceAVC())
|
private val DEVICE_MODEL_IOS = if (forceAVC())
|
||||||
"iPhone12,5" // 11 Pro Max. (last device with iOS 13)
|
"iPhone12,5" // 11 Pro Max. (last device with iOS 13)
|
||||||
else
|
else
|
||||||
"iPhone16,2" // 15 Pro Max.
|
"iPhone17,2" // 16 Pro Max.
|
||||||
private val OS_VERSION_IOS = if (forceAVC())
|
private val OS_VERSION_IOS = if (forceAVC())
|
||||||
"13.7.17H35" // Last release of iOS 13.
|
"13.7.17H35" // Last release of iOS 13.
|
||||||
else
|
else
|
||||||
"17.7.2.21H221"
|
"18.3.2.22D82"
|
||||||
private val USER_AGENT_VERSION_IOS = if (forceAVC())
|
private val USER_AGENT_VERSION_IOS = if (forceAVC())
|
||||||
"13_7"
|
"13_7"
|
||||||
else
|
else
|
||||||
"17_7_2"
|
"18_3_2"
|
||||||
private val USER_AGENT_IOS = iOSUserAgent(PACKAGE_NAME_IOS, CLIENT_VERSION_IOS)
|
private val USER_AGENT_IOS = iOSUserAgent(PACKAGE_NAME_IOS, CLIENT_VERSION_IOS)
|
||||||
|
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ object YouTubeAppClient {
|
|||||||
private val CLIENT_VERSION_IOS_UNPLUGGED = if (forceAVC())
|
private val CLIENT_VERSION_IOS_UNPLUGGED = if (forceAVC())
|
||||||
"6.45"
|
"6.45"
|
||||||
else
|
else
|
||||||
"8.33"
|
"9.10"
|
||||||
private val USER_AGENT_IOS_UNPLUGGED =
|
private val USER_AGENT_IOS_UNPLUGGED =
|
||||||
iOSUserAgent(PACKAGE_NAME_IOS_UNPLUGGED, CLIENT_VERSION_IOS_UNPLUGGED)
|
iOSUserAgent(PACKAGE_NAME_IOS_UNPLUGGED, CLIENT_VERSION_IOS_UNPLUGGED)
|
||||||
|
|
||||||
@ -92,35 +92,31 @@ object YouTubeAppClient {
|
|||||||
* Package name for YouTube VR (Meta Quests): com.google.android.apps.youtube.vr.oculus
|
* Package name for YouTube VR (Meta Quests): com.google.android.apps.youtube.vr.oculus
|
||||||
* Package name for YouTube VR (ByteDance Pico): com.google.android.apps.youtube.vr.pico
|
* Package name for YouTube VR (ByteDance Pico): com.google.android.apps.youtube.vr.pico
|
||||||
*/
|
*/
|
||||||
private const val PACKAGE_NAME_ANDROID_VR = "com.google.android.apps.youtube.vr.pico"
|
private const val PACKAGE_NAME_ANDROID_VR = "com.google.android.apps.youtube.vr.oculus"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The hardcoded client version of the Android VR app used for InnerTube requests with this client.
|
* The hardcoded client version of the Android VR app used for InnerTube requests with this client.
|
||||||
*
|
*
|
||||||
* It can be extracted by getting the latest release version of the app on
|
* It can be extracted by getting the latest release version of the app on
|
||||||
* [the App Store page of the YouTube VR app](https://store-global.picoxr.com/en/detail/1/7270207384512020485/),
|
* [the App Store page of the YouTube app](https://www.meta.com/en-us/experiences/2002317119880945/),
|
||||||
* in the `Information` section.
|
* in the `Additional details` section.
|
||||||
*/
|
*/
|
||||||
private const val CLIENT_VERSION_ANDROID_VR = "1.62.27"
|
private const val CLIENT_VERSION_ANDROID_VR = "1.62.27"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The device machine id for the Pico 4 Ultra.
|
* The device machine id for the Meta Quest 3, used to get opus codec with the Android VR client.
|
||||||
*
|
* See [this GitLab](https://dumps.tadiphone.dev/dumps/oculus/eureka) for more information.
|
||||||
* For Pico 4 Ultra, there is no public firmware archive yet.
|
|
||||||
* The device machine id is taken from [this repository](https://github.com/Genymobile/scrcpy/issues/5659).
|
|
||||||
* The OS version and build ID are taken from [the signature key of OTA firmware](https://pico.crx.moe/docs/picoos-research/version-table#pico-4-ultra-series).
|
|
||||||
*/
|
*/
|
||||||
private const val DEVICE_MODEL_ANDROID_VR = "A9210"
|
private const val DEVICE_MODEL_ANDROID_VR = "Quest 3"
|
||||||
|
private const val DEVICE_MAKE_ANDROID_VR = "Oculus"
|
||||||
|
private const val OS_VERSION_ANDROID_VR = "12"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The manufacturer is 'ByteDance', but the build prop is marked as 'Pico'.
|
* The SDK version for Android 12 is 31,
|
||||||
|
* but for some reason the build.props for the `Quest 3` state that the SDK version is 32.
|
||||||
*/
|
*/
|
||||||
private const val DEVICE_MAKE_ANDROID_VR = "Pico"
|
private const val ANDROID_SDK_VERSION_ANDROID_VR = "32"
|
||||||
private const val OS_VERSION_ANDROID_VR = "14"
|
private const val BUILD_ID_ANDROID_VR = "SQ3A.220605.009.A1"
|
||||||
private const val ANDROID_SDK_VERSION_ANDROID_VR = "34"
|
|
||||||
/**
|
|
||||||
* PICO OS 5.12.6 (Android 14)
|
|
||||||
*/
|
|
||||||
private const val BUILD_ID_ANDROID_VR = "UKQ1.240321.001"
|
|
||||||
|
|
||||||
private val USER_AGENT_ANDROID_VR = androidUserAgent(
|
private val USER_AGENT_ANDROID_VR = androidUserAgent(
|
||||||
packageName = PACKAGE_NAME_ANDROID_VR,
|
packageName = PACKAGE_NAME_ANDROID_VR,
|
||||||
@ -137,7 +133,7 @@ object YouTubeAppClient {
|
|||||||
* Note: Audio track is not available
|
* Note: Audio track is not available
|
||||||
*/
|
*/
|
||||||
private const val PACKAGE_NAME_ANDROID_UNPLUGGED = "com.google.android.apps.youtube.unplugged"
|
private const val PACKAGE_NAME_ANDROID_UNPLUGGED = "com.google.android.apps.youtube.unplugged"
|
||||||
private const val CLIENT_VERSION_ANDROID_UNPLUGGED = "8.16.0"
|
private const val CLIENT_VERSION_ANDROID_UNPLUGGED = "9.09.1"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The device machine id for the Chromecast with Google TV 4K.
|
* The device machine id for the Chromecast with Google TV 4K.
|
||||||
@ -147,8 +143,8 @@ object YouTubeAppClient {
|
|||||||
private const val DEVICE_MAKE_ANDROID_UNPLUGGED = "Google"
|
private const val DEVICE_MAKE_ANDROID_UNPLUGGED = "Google"
|
||||||
private const val OS_VERSION_ANDROID_UNPLUGGED = "14"
|
private const val OS_VERSION_ANDROID_UNPLUGGED = "14"
|
||||||
private const val ANDROID_SDK_VERSION_ANDROID_UNPLUGGED = "34"
|
private const val ANDROID_SDK_VERSION_ANDROID_UNPLUGGED = "34"
|
||||||
private const val BUILD_ID_ANDROID_UNPLUGGED = "UTT3.240625.001.K5"
|
private const val BUILD_ID_ANDROID_UNPLUGGED = "UTTK.241210.003"
|
||||||
private const val GMS_CORE_VERSION_CODE_ANDROID_UNPLUGGED = "244336107"
|
private const val GMS_CORE_VERSION_CODE_ANDROID_UNPLUGGED = "244738119"
|
||||||
|
|
||||||
private val USER_AGENT_ANDROID_UNPLUGGED = androidUserAgent(
|
private val USER_AGENT_ANDROID_UNPLUGGED = androidUserAgent(
|
||||||
packageName = PACKAGE_NAME_ANDROID_UNPLUGGED,
|
packageName = PACKAGE_NAME_ANDROID_UNPLUGGED,
|
||||||
@ -165,7 +161,7 @@ object YouTubeAppClient {
|
|||||||
* Note: Audio track is not available
|
* Note: Audio track is not available
|
||||||
*/
|
*/
|
||||||
private const val PACKAGE_NAME_ANDROID_CREATOR = "com.google.android.apps.youtube.creator"
|
private const val PACKAGE_NAME_ANDROID_CREATOR = "com.google.android.apps.youtube.creator"
|
||||||
private const val CLIENT_VERSION_ANDROID_CREATOR = "23.47.101"
|
private const val CLIENT_VERSION_ANDROID_CREATOR = "25.10.100"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The device machine id for the Google Pixel 9 Pro Fold.
|
* The device machine id for the Google Pixel 9 Pro Fold.
|
||||||
@ -176,7 +172,7 @@ object YouTubeAppClient {
|
|||||||
private const val OS_VERSION_ANDROID_CREATOR = "15"
|
private const val OS_VERSION_ANDROID_CREATOR = "15"
|
||||||
private const val ANDROID_SDK_VERSION_ANDROID_CREATOR = "35"
|
private const val ANDROID_SDK_VERSION_ANDROID_CREATOR = "35"
|
||||||
private const val BUILD_ID_ANDROID_CREATOR = "AP3A.241005.015.A2"
|
private const val BUILD_ID_ANDROID_CREATOR = "AP3A.241005.015.A2"
|
||||||
private const val GMS_CORE_VERSION_CODE_ANDROID_CREATOR = "244738035"
|
private const val GMS_CORE_VERSION_CODE_ANDROID_CREATOR = "250932035"
|
||||||
|
|
||||||
private val USER_AGENT_ANDROID_CREATOR = androidUserAgent(
|
private val USER_AGENT_ANDROID_CREATOR = androidUserAgent(
|
||||||
packageName = PACKAGE_NAME_ANDROID_CREATOR,
|
packageName = PACKAGE_NAME_ANDROID_CREATOR,
|
||||||
|
@ -23,6 +23,8 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
|
|||||||
BaseSettings.SPOOF_STREAMING_DATA_PO_TOKEN.get();
|
BaseSettings.SPOOF_STREAMING_DATA_PO_TOKEN.get();
|
||||||
private static final String VISITOR_DATA =
|
private static final String VISITOR_DATA =
|
||||||
BaseSettings.SPOOF_STREAMING_DATA_VISITOR_DATA.get();
|
BaseSettings.SPOOF_STREAMING_DATA_VISITOR_DATA.get();
|
||||||
|
private static final boolean SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION =
|
||||||
|
SPOOF_STREAMING_DATA && BaseSettings.SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION.get();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Any unreachable ip address. Used to intentionally fail requests.
|
* Any unreachable ip address. Used to intentionally fail requests.
|
||||||
@ -67,11 +69,11 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
|
|||||||
* Skip response encryption in OnesiePlayerRequest.
|
* Skip response encryption in OnesiePlayerRequest.
|
||||||
*/
|
*/
|
||||||
public static boolean skipResponseEncryption(boolean original) {
|
public static boolean skipResponseEncryption(boolean original) {
|
||||||
if (!SPOOF_STREAMING_DATA) {
|
if (SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION) {
|
||||||
return original;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,6 +88,7 @@ object PlayerRoutes {
|
|||||||
botGuardPoToken: String = "",
|
botGuardPoToken: String = "",
|
||||||
visitorId: String = "",
|
visitorId: String = "",
|
||||||
setLocale: Boolean = false,
|
setLocale: Boolean = false,
|
||||||
|
language: String = BaseSettings.SPOOF_STREAMING_DATA_LANGUAGE.get().language,
|
||||||
): ByteArray {
|
): ByteArray {
|
||||||
val innerTubeBody = JSONObject()
|
val innerTubeBody = JSONObject()
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ object PlayerRoutes {
|
|||||||
client.put(
|
client.put(
|
||||||
"hl",
|
"hl",
|
||||||
if (setLocale) {
|
if (setLocale) {
|
||||||
BaseSettings.SPOOF_STREAMING_DATA_LANGUAGE.get().language
|
language
|
||||||
} else {
|
} else {
|
||||||
LOCALE_LANGUAGE
|
LOCALE_LANGUAGE
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ public class BaseSettings {
|
|||||||
* These settings are used by YouTube Music.
|
* These settings are used by YouTube Music.
|
||||||
* Some patches are in a shared path, so they are declared here.
|
* Some patches are in a shared path, so they are declared here.
|
||||||
*/
|
*/
|
||||||
public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", TRUE, true);
|
public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", FALSE, true);
|
||||||
public static final EnumSetting<MusicAppClient.ClientType> SPOOF_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_client_type", MusicAppClient.ClientType.IOS_MUSIC_6_21, true);
|
public static final EnumSetting<MusicAppClient.ClientType> SPOOF_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_client_type", MusicAppClient.ClientType.IOS_MUSIC_6_21, true);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -41,6 +41,7 @@ public class BaseSettings {
|
|||||||
public static final EnumSetting<AppLanguage> SPOOF_STREAMING_DATA_LANGUAGE = new EnumSetting<>("revanced_spoof_streaming_data_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
public static final EnumSetting<AppLanguage> SPOOF_STREAMING_DATA_LANGUAGE = new EnumSetting<>("revanced_spoof_streaming_data_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
||||||
public static final BooleanSetting SPOOF_STREAMING_DATA_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_streaming_data_ios_force_avc", FALSE, true,
|
public static final BooleanSetting SPOOF_STREAMING_DATA_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_streaming_data_ios_force_avc", FALSE, true,
|
||||||
"revanced_spoof_streaming_data_ios_force_avc_user_dialog_message");
|
"revanced_spoof_streaming_data_ios_force_avc_user_dialog_message");
|
||||||
|
public static final BooleanSetting SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION = new BooleanSetting("revanced_spoof_streaming_data_skip_response_encryption", TRUE, true);
|
||||||
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE);
|
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE);
|
||||||
// Client type must be last spoof setting due to cyclic references.
|
// Client type must be last spoof setting due to cyclic references.
|
||||||
public static final EnumSetting<YouTubeAppClient.ClientType> SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", YouTubeAppClient.ClientType.ANDROID_UNPLUGGED, true);
|
public static final EnumSetting<YouTubeAppClient.ClientType> SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", YouTubeAppClient.ClientType.ANDROID_UNPLUGGED, true);
|
||||||
|
@ -24,9 +24,6 @@ import app.revanced.extension.shared.utils.Logger;
|
|||||||
import app.revanced.extension.shared.utils.StringRef;
|
import app.revanced.extension.shared.utils.StringRef;
|
||||||
import app.revanced.extension.shared.utils.Utils;
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
|
||||||
/**
|
|
||||||
* @noinspection rawtypes
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public abstract class Setting<T> {
|
public abstract class Setting<T> {
|
||||||
|
|
||||||
@ -128,6 +125,7 @@ public abstract class Setting<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @return All settings that have been created, sorted by keys.
|
* @return All settings that have been created, sorted by keys.
|
||||||
|
* @noinspection Java8ListSort
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private static List<Setting<?>> allLoadedSettingsSorted() {
|
private static List<Setting<?>> allLoadedSettingsSorted() {
|
||||||
@ -171,7 +169,6 @@ public abstract class Setting<T> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirmation message to display, if the user tries to change the setting from the default value.
|
* Confirmation message to display, if the user tries to change the setting from the default value.
|
||||||
* Currently this works only for Boolean setting types.
|
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
public final StringRef userDialogMessage;
|
public final StringRef userDialogMessage;
|
||||||
@ -271,6 +268,7 @@ public abstract class Setting<T> {
|
|||||||
* <p>
|
* <p>
|
||||||
* This method will be deleted in the future.
|
* This method will be deleted in the future.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
public static void migrateFromOldPreferences(@NonNull SharedPrefCategory oldPrefs, @NonNull Setting setting, String settingKey) {
|
public static void migrateFromOldPreferences(@NonNull SharedPrefCategory oldPrefs, @NonNull Setting setting, String settingKey) {
|
||||||
if (!oldPrefs.preferences.contains(settingKey)) {
|
if (!oldPrefs.preferences.contains(settingKey)) {
|
||||||
return; // Nothing to do.
|
return; // Nothing to do.
|
||||||
@ -452,6 +450,7 @@ public abstract class Setting<T> {
|
|||||||
|
|
||||||
boolean rebootSettingChanged = false;
|
boolean rebootSettingChanged = false;
|
||||||
int numberOfSettingsImported = 0;
|
int numberOfSettingsImported = 0;
|
||||||
|
//noinspection rawtypes
|
||||||
for (Setting setting : SETTINGS) {
|
for (Setting setting : SETTINGS) {
|
||||||
String key = setting.getImportExportKey();
|
String key = setting.getImportExportKey();
|
||||||
if (json.has(key)) {
|
if (json.has(key)) {
|
||||||
|
@ -12,6 +12,7 @@ import android.preference.EditTextPreference;
|
|||||||
import android.preference.ListPreference;
|
import android.preference.ListPreference;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceFragment;
|
import android.preference.PreferenceFragment;
|
||||||
|
import android.preference.PreferenceGroup;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
@ -21,6 +22,9 @@ import android.widget.ListView;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.shared.settings.BooleanSetting;
|
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||||
import app.revanced.extension.shared.settings.Setting;
|
import app.revanced.extension.shared.settings.Setting;
|
||||||
import app.revanced.extension.shared.utils.Logger;
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
@ -48,10 +52,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
|
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
|
||||||
try {
|
try {
|
||||||
if (str == null) {
|
Setting<?> setting = Setting.getSettingFromPath(Objects.requireNonNull(str));
|
||||||
return;
|
|
||||||
}
|
|
||||||
Setting<?> setting = Setting.getSettingFromPath(str);
|
|
||||||
if (setting == null) {
|
if (setting == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -59,24 +60,23 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
if (pref == null) {
|
if (pref == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Logger.printDebug(() -> "Preference changed: " + setting.key);
|
||||||
|
|
||||||
|
if (!settingImportInProgress && !showingUserDialogMessage) {
|
||||||
|
if (setting.userDialogMessage != null && !prefIsSetToDefault(pref, setting)) {
|
||||||
|
// Do not change the setting yet, to allow preserving whatever
|
||||||
|
// list/text value was previously set if it needs to be reverted.
|
||||||
|
showSettingUserDialogConfirmation(pref, setting);
|
||||||
|
return;
|
||||||
|
} else if (setting.rebootApp) {
|
||||||
|
showRestartDialog(getContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
|
// Apply 'Setting <- Preference', unless during importing when it needs to be 'Setting -> Preference'.
|
||||||
updatePreference(pref, setting, true, settingImportInProgress);
|
updatePreference(pref, setting, true, settingImportInProgress);
|
||||||
// Update any other preference availability that may now be different.
|
// Update any other preference availability that may now be different.
|
||||||
updateUIAvailability();
|
updateUIAvailability();
|
||||||
|
|
||||||
if (settingImportInProgress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!showingUserDialogMessage) {
|
|
||||||
if (setting.userDialogMessage != null && ((SwitchPreference) pref).isChecked() != (Boolean) setting.defaultValue) {
|
|
||||||
showSettingUserDialogConfirmation((SwitchPreference) pref, (BooleanSetting) setting);
|
|
||||||
} else if (setting.rebootApp) {
|
|
||||||
showRestartDialog(getActivity());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
Logger.printException(() -> "OnSharedPreferenceChangeListener failure", ex);
|
Logger.printException(() -> "OnSharedPreferenceChangeListener failure", ex);
|
||||||
}
|
}
|
||||||
@ -90,14 +90,16 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
* so all app specific {@link Setting} instances are loaded before this method returns.
|
* so all app specific {@link Setting} instances are loaded before this method returns.
|
||||||
*/
|
*/
|
||||||
protected void initialize() {
|
protected void initialize() {
|
||||||
final int id = getXmlIdentifier("revanced_prefs");
|
final int identifier = getXmlIdentifier("revanced_prefs");
|
||||||
|
if (identifier == 0) return;
|
||||||
|
addPreferencesFromResource(identifier);
|
||||||
|
|
||||||
if (id == 0) return;
|
PreferenceScreen screen = getPreferenceScreen();
|
||||||
addPreferencesFromResource(id);
|
Utils.sortPreferenceGroups(screen);
|
||||||
Utils.sortPreferenceGroups(getPreferenceScreen());
|
Utils.setPreferenceTitlesToMultiLineIfNeeded(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSettingUserDialogConfirmation(SwitchPreference switchPref, BooleanSetting setting) {
|
private void showSettingUserDialogConfirmation(Preference pref, Setting<?> setting) {
|
||||||
Utils.verifyOnMainThread();
|
Utils.verifyOnMainThread();
|
||||||
|
|
||||||
final var context = getActivity();
|
final var context = getActivity();
|
||||||
@ -107,12 +109,19 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
.setTitle(android.R.string.dialog_alert_title)
|
.setTitle(android.R.string.dialog_alert_title)
|
||||||
.setMessage(setting.userDialogMessage.toString())
|
.setMessage(setting.userDialogMessage.toString())
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
|
.setPositiveButton(android.R.string.ok, (dialog, id) -> {
|
||||||
|
// User confirmed, save to the Setting.
|
||||||
|
updatePreference(pref, setting, true, false);
|
||||||
|
|
||||||
|
// Update availability of other preferences that may be changed.
|
||||||
|
updateUIAvailability();
|
||||||
|
|
||||||
if (setting.rebootApp) {
|
if (setting.rebootApp) {
|
||||||
showRestartDialog(context);
|
showRestartDialog(context);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {
|
.setNegativeButton(android.R.string.cancel, (dialog, id) -> {
|
||||||
switchPref.setChecked(setting.defaultValue); // Recursive call that resets the Setting value.
|
// Restore whatever the setting was before the change.
|
||||||
|
updatePreference(pref, setting, true, true);
|
||||||
})
|
})
|
||||||
.setOnDismissListener(dialog -> showingUserDialogMessage = false)
|
.setOnDismissListener(dialog -> showingUserDialogMessage = false)
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
@ -123,7 +132,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
* Updates all Preferences values and their availability using the current values in {@link Setting}.
|
* Updates all Preferences values and their availability using the current values in {@link Setting}.
|
||||||
*/
|
*/
|
||||||
protected void updateUIToSettingValues() {
|
protected void updateUIToSettingValues() {
|
||||||
updatePreferenceScreen(getPreferenceScreen(), true, true);
|
updatePreferenceScreen(getPreferenceScreen(), true,true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -133,24 +142,48 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
updatePreferenceScreen(getPreferenceScreen(), false, false);
|
updatePreferenceScreen(getPreferenceScreen(), false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return If the preference is currently set to the default value of the Setting.
|
||||||
|
*/
|
||||||
|
protected boolean prefIsSetToDefault(Preference pref, Setting<?> setting) {
|
||||||
|
if (pref instanceof SwitchPreference switchPref) {
|
||||||
|
return switchPref.isChecked() == (Boolean) setting.defaultValue;
|
||||||
|
}
|
||||||
|
if (pref instanceof EditTextPreference editPreference) {
|
||||||
|
return editPreference.getText().equals(setting.defaultValue.toString());
|
||||||
|
}
|
||||||
|
if (pref instanceof ListPreference listPref) {
|
||||||
|
return listPref.getValue().equals(setting.defaultValue.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Must override method to handle "
|
||||||
|
+ "preference type: " + pref.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syncs all UI Preferences to any {@link Setting} they represent.
|
* Syncs all UI Preferences to any {@link Setting} they represent.
|
||||||
*/
|
*/
|
||||||
private void updatePreferenceScreen(@NonNull PreferenceScreen screen,
|
private void updatePreferenceScreen(@NonNull PreferenceGroup group,
|
||||||
boolean syncSettingValue,
|
boolean syncSettingValue,
|
||||||
boolean applySettingToPreference) {
|
boolean applySettingToPreference) {
|
||||||
// Alternatively this could iterate thru all Settings and check for any matching Preferences,
|
// Alternatively this could iterate thru all Settings and check for any matching Preferences,
|
||||||
// but there are many more Settings than UI preferences so it's more efficient to only check
|
// but there are many more Settings than UI preferences so it's more efficient to only check
|
||||||
// the Preferences.
|
// the Preferences.
|
||||||
for (int i = 0, prefCount = screen.getPreferenceCount(); i < prefCount; i++) {
|
for (int i = 0, prefCount = group.getPreferenceCount(); i < prefCount; i++) {
|
||||||
Preference pref = screen.getPreference(i);
|
Preference pref = group.getPreference(i);
|
||||||
if (pref instanceof PreferenceScreen preferenceScreen) {
|
if (pref instanceof PreferenceGroup subGroup) {
|
||||||
updatePreferenceScreen(preferenceScreen, syncSettingValue, applySettingToPreference);
|
updatePreferenceScreen(subGroup, syncSettingValue, applySettingToPreference);
|
||||||
} else if (pref.hasKey()) {
|
} else if (pref.hasKey()) {
|
||||||
String key = pref.getKey();
|
String key = pref.getKey();
|
||||||
Setting<?> setting = Setting.getSettingFromPath(key);
|
Setting<?> setting = Setting.getSettingFromPath(key);
|
||||||
|
|
||||||
if (setting != null) {
|
if (setting != null) {
|
||||||
updatePreference(pref, setting, syncSettingValue, applySettingToPreference);
|
updatePreference(pref, setting, syncSettingValue, applySettingToPreference);
|
||||||
|
} else if (BaseSettings.ENABLE_DEBUG_LOGGING.get() && (pref instanceof SwitchPreference
|
||||||
|
|| pref instanceof EditTextPreference || pref instanceof ListPreference)) {
|
||||||
|
// Probably a typo in the patches preference declaration.
|
||||||
|
Logger.printException(() -> "Preference key has no setting: " + key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,26 +199,26 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
|
|||||||
protected void syncSettingWithPreference(@NonNull Preference pref,
|
protected void syncSettingWithPreference(@NonNull Preference pref,
|
||||||
@NonNull Setting<?> setting,
|
@NonNull Setting<?> setting,
|
||||||
boolean applySettingToPreference) {
|
boolean applySettingToPreference) {
|
||||||
if (pref instanceof SwitchPreference switchPreference) {
|
if (pref instanceof SwitchPreference switchPref) {
|
||||||
BooleanSetting boolSetting = (BooleanSetting) setting;
|
BooleanSetting boolSetting = (BooleanSetting) setting;
|
||||||
if (applySettingToPreference) {
|
if (applySettingToPreference) {
|
||||||
switchPreference.setChecked(boolSetting.get());
|
switchPref.setChecked(boolSetting.get());
|
||||||
} else {
|
} else {
|
||||||
BooleanSetting.privateSetValue(boolSetting, switchPreference.isChecked());
|
BooleanSetting.privateSetValue(boolSetting, switchPref.isChecked());
|
||||||
}
|
}
|
||||||
} else if (pref instanceof EditTextPreference editTextPreference) {
|
} else if (pref instanceof EditTextPreference editPreference) {
|
||||||
if (applySettingToPreference) {
|
if (applySettingToPreference) {
|
||||||
editTextPreference.setText(setting.get().toString());
|
editPreference.setText(setting.get().toString());
|
||||||
} else {
|
} else {
|
||||||
Setting.privateSetValueFromString(setting, editTextPreference.getText());
|
Setting.privateSetValueFromString(setting, editPreference.getText());
|
||||||
}
|
}
|
||||||
} else if (pref instanceof ListPreference listPreference) {
|
} else if (pref instanceof ListPreference listPref) {
|
||||||
if (applySettingToPreference) {
|
if (applySettingToPreference) {
|
||||||
listPreference.setValue(setting.get().toString());
|
listPref.setValue(setting.get().toString());
|
||||||
} else {
|
} else {
|
||||||
Setting.privateSetValueFromString(setting, listPreference.getValue());
|
Setting.privateSetValueFromString(setting, listPref.getValue());
|
||||||
}
|
}
|
||||||
updateListPreferenceSummary(listPreference, setting);
|
updateListPreferenceSummary(listPref, setting);
|
||||||
} else {
|
} else {
|
||||||
Logger.printException(() -> "Setting cannot be handled: " + pref.getClass() + ": " + pref);
|
Logger.printException(() -> "Setting cannot be handled: " + pref.getClass() + ": " + pref);
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import android.view.animation.Animation;
|
|||||||
import android.view.animation.AnimationUtils;
|
import android.view.animation.AnimationUtils;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
@SuppressWarnings({"unused", "deprecation", "DiscouragedApi"})
|
@SuppressWarnings({"unused", "deprecation", "DiscouragedApi"})
|
||||||
public class ResourceUtils extends Utils {
|
public class ResourceUtils extends Utils {
|
||||||
@ -100,13 +101,19 @@ public class ResourceUtils extends Utils {
|
|||||||
return getIdentifier(str, ResourceType.XML);
|
return getIdentifier(str, ResourceType.XML);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public static Animation getAnimation(@NonNull String str) {
|
public static Animation getAnimation(@NonNull String str) {
|
||||||
|
try {
|
||||||
int identifier = getAnimIdentifier(str);
|
int identifier = getAnimIdentifier(str);
|
||||||
if (identifier == 0) {
|
if (identifier == 0) {
|
||||||
handleException(str, ResourceType.ANIM);
|
handleException(str, ResourceType.ANIM);
|
||||||
identifier = android.R.anim.fade_in;
|
identifier = android.R.anim.fade_in;
|
||||||
}
|
}
|
||||||
return AnimationUtils.loadAnimation(getContext(), identifier);
|
return AnimationUtils.loadAnimation(getContext(), identifier);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
handleException(str, ResourceType.ANIM);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getColor(@NonNull String str) {
|
public static int getColor(@NonNull String str) {
|
||||||
|
@ -3,6 +3,8 @@ package app.revanced.extension.shared.utils;
|
|||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
import android.app.Fragment;
|
import android.app.Fragment;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
@ -13,11 +15,14 @@ import android.net.ConnectivityManager;
|
|||||||
import android.net.NetworkInfo;
|
import android.net.NetworkInfo;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.preference.Preference;
|
import android.preference.Preference;
|
||||||
import android.preference.PreferenceGroup;
|
import android.preference.PreferenceGroup;
|
||||||
import android.preference.PreferenceScreen;
|
import android.preference.PreferenceScreen;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.Spanned;
|
||||||
import android.util.TypedValue;
|
import android.util.TypedValue;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@ -43,17 +48,18 @@ import java.util.concurrent.Future;
|
|||||||
import java.util.concurrent.SynchronousQueue;
|
import java.util.concurrent.SynchronousQueue;
|
||||||
import java.util.concurrent.ThreadPoolExecutor;
|
import java.util.concurrent.ThreadPoolExecutor;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import app.revanced.extension.shared.settings.AppLanguage;
|
import app.revanced.extension.shared.settings.AppLanguage;
|
||||||
import app.revanced.extension.shared.settings.BaseSettings;
|
import app.revanced.extension.shared.settings.BaseSettings;
|
||||||
import app.revanced.extension.shared.settings.BooleanSetting;
|
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||||
import kotlin.text.Regex;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public class Utils {
|
public class Utils {
|
||||||
|
|
||||||
private static WeakReference<Activity> activityRef = new WeakReference<>(null);
|
private static WeakReference<Activity> activityRef = new WeakReference<>(null);
|
||||||
private static WeakReference<Context> contextRef = new WeakReference<>(null);
|
@SuppressLint("StaticFieldLeak")
|
||||||
|
private static volatile Context context;
|
||||||
|
|
||||||
protected Utils() {
|
protected Utils() {
|
||||||
} // utility class
|
} // utility class
|
||||||
@ -274,17 +280,15 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static Context getContext() {
|
public static Context getContext() {
|
||||||
Context mContext = contextRef.get();
|
if (context == null) {
|
||||||
if (mContext == null) {
|
|
||||||
Logger.initializationException(Utils.class, "Context is null, returning null!", null);
|
Logger.initializationException(Utils.class, "Context is null, returning null!", null);
|
||||||
}
|
}
|
||||||
return mContext;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Resources getResources() {
|
public static Resources getResources() {
|
||||||
Context mContext = contextRef.get();
|
if (context != null) {
|
||||||
if (mContext != null) {
|
return context.getResources();
|
||||||
return mContext.getResources();
|
|
||||||
}
|
}
|
||||||
Activity mActivity = activityRef.get();
|
Activity mActivity = activityRef.get();
|
||||||
if (mActivity != null) {
|
if (mActivity != null) {
|
||||||
@ -347,7 +351,7 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Must initially set context to check the app language.
|
// Must initially set context to check the app language.
|
||||||
contextRef = new WeakReference<>(appContext);
|
context = appContext;
|
||||||
Logger.initializationInfo(Utils.class, "Set context: " + appContext);
|
Logger.initializationInfo(Utils.class, "Set context: " + appContext);
|
||||||
|
|
||||||
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
|
AppLanguage language = BaseSettings.REVANCED_LANGUAGE.get();
|
||||||
@ -355,7 +359,7 @@ public class Utils {
|
|||||||
// Create a new context with the desired language.
|
// Create a new context with the desired language.
|
||||||
Configuration config = appContext.getResources().getConfiguration();
|
Configuration config = appContext.getResources().getConfiguration();
|
||||||
config.setLocale(language.getLocale());
|
config.setLocale(language.getLocale());
|
||||||
contextRef = new WeakReference<>(appContext.createConfigurationContext(config));
|
context = appContext.createConfigurationContext(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -364,8 +368,7 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void setClipboard(@NonNull String text, @Nullable String toastMessage) {
|
public static void setClipboard(@NonNull String text, @Nullable String toastMessage) {
|
||||||
Context mContext = contextRef.get();
|
if (context != null && context.getSystemService(Context.CLIPBOARD_SERVICE) instanceof ClipboardManager clipboardManager) {
|
||||||
if (mContext != null && mContext.getSystemService(Context.CLIPBOARD_SERVICE) instanceof ClipboardManager clipboardManager) {
|
|
||||||
android.content.ClipData clip = android.content.ClipData.newPlainText("ReVanced", text);
|
android.content.ClipData clip = android.content.ClipData.newPlainText("ReVanced", text);
|
||||||
clipboardManager.setPrimaryClip(clip);
|
clipboardManager.setPrimaryClip(clip);
|
||||||
|
|
||||||
@ -508,6 +511,26 @@ public class Utils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CharSequence newSpanUsingStylingOfAnotherSpan(@Nullable CharSequence sourceStyle, @NonNull CharSequence newSpanText) {
|
||||||
|
if (sourceStyle instanceof Spanned spanned) {
|
||||||
|
return newSpanUsingStylingOfAnotherSpan(spanned, newSpanText);
|
||||||
|
}
|
||||||
|
return sourceStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SpannableString newSpanUsingStylingOfAnotherSpan(@NonNull Spanned sourceStyle, @NonNull CharSequence newSpanText) {
|
||||||
|
if (sourceStyle == newSpanText && sourceStyle instanceof SpannableString spannableString) {
|
||||||
|
return spannableString; // Nothing to do.
|
||||||
|
}
|
||||||
|
SpannableString destination = new SpannableString(newSpanText);
|
||||||
|
Object[] spans = sourceStyle.getSpans(0, sourceStyle.length(), Object.class);
|
||||||
|
for (Object span : spans) {
|
||||||
|
destination.setSpan(span, 0, destination.length(), sourceStyle.getSpanFlags(span));
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return whether the device's API level is higher than a specific SDK version.
|
* @return whether the device's API level is higher than a specific SDK version.
|
||||||
*/
|
*/
|
||||||
@ -516,23 +539,96 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int dpToPx(float dp) {
|
public static int dpToPx(float dp) {
|
||||||
Context mContext = contextRef.get();
|
if (context == null) {
|
||||||
if (mContext == null) {
|
|
||||||
return (int) dp;
|
return (int) dp;
|
||||||
} else {
|
} else {
|
||||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics());
|
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int dpToPx(int dp) {
|
public static int dpToPx(int dp) {
|
||||||
Context mContext = contextRef.get();
|
if (context == null) {
|
||||||
if (mContext == null) {
|
|
||||||
return dp;
|
return dp;
|
||||||
} else {
|
} else {
|
||||||
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, mContext.getResources().getDisplayMetrics());
|
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ignore this class. It must be public to satisfy Android requirements.
|
||||||
|
*/
|
||||||
|
public static final class DialogFragmentWrapper extends DialogFragment {
|
||||||
|
|
||||||
|
private Dialog dialog;
|
||||||
|
@Nullable
|
||||||
|
private DialogFragmentOnStartAction onStartAction;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(Bundle outState) {
|
||||||
|
// Do not call super method to prevent state saving.
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
return dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStart() {
|
||||||
|
try {
|
||||||
|
super.onStart();
|
||||||
|
|
||||||
|
if (onStartAction != null) {
|
||||||
|
onStartAction.onStart((AlertDialog) getDialog());
|
||||||
|
}
|
||||||
|
} catch (Exception ex) {
|
||||||
|
Logger.printException(() -> "onStart failure: " + dialog.getClass().getSimpleName(), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for {@link #showDialog(Activity, AlertDialog, boolean, DialogFragmentOnStartAction)}.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface DialogFragmentOnStartAction {
|
||||||
|
void onStart(AlertDialog dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void showDialog(Activity activity, AlertDialog dialog) {
|
||||||
|
showDialog(activity, dialog, true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility method to allow showing an AlertDialog on top of other alert dialogs.
|
||||||
|
* Calling this will always display the dialog on top of all other dialogs
|
||||||
|
* previously called using this method.
|
||||||
|
* <br>
|
||||||
|
* Be aware the on start action can be called multiple times for some situations,
|
||||||
|
* such as the user switching apps without dismissing the dialog then switching back to this app.
|
||||||
|
*<br>
|
||||||
|
* This method is only useful during app startup and multiple patches may show their own dialog,
|
||||||
|
* and the most important dialog can be called last (using a delay) so it's always on top.
|
||||||
|
*<br>
|
||||||
|
* For all other situations it's better to not use this method and
|
||||||
|
* call {@link AlertDialog#show()} on the dialog.
|
||||||
|
*/
|
||||||
|
public static void showDialog(Activity activity,
|
||||||
|
AlertDialog dialog,
|
||||||
|
boolean isCancelable,
|
||||||
|
@Nullable DialogFragmentOnStartAction onStartAction) {
|
||||||
|
verifyOnMainThread();
|
||||||
|
|
||||||
|
DialogFragmentWrapper fragment = new DialogFragmentWrapper();
|
||||||
|
fragment.dialog = dialog;
|
||||||
|
fragment.onStartAction = onStartAction;
|
||||||
|
fragment.setCancelable(isCancelable);
|
||||||
|
|
||||||
|
fragment.show(activity.getFragmentManager(), null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Safe to call from any thread
|
* Safe to call from any thread
|
||||||
*/
|
*/
|
||||||
@ -550,20 +646,18 @@ public class Utils {
|
|||||||
private static void showToast(@NonNull String messageToToast, int toastDuration) {
|
private static void showToast(@NonNull String messageToToast, int toastDuration) {
|
||||||
Objects.requireNonNull(messageToToast);
|
Objects.requireNonNull(messageToToast);
|
||||||
runOnMainThreadNowOrLater(() -> {
|
runOnMainThreadNowOrLater(() -> {
|
||||||
Context mContext = contextRef.get();
|
if (context == null) {
|
||||||
if (mContext == null) {
|
|
||||||
Logger.initializationException(Utils.class, "Cannot show toast (context is null): " + messageToToast, null);
|
Logger.initializationException(Utils.class, "Cannot show toast (context is null): " + messageToToast, null);
|
||||||
} else {
|
} else {
|
||||||
Logger.printDebug(() -> "Showing toast: " + messageToToast);
|
Logger.printDebug(() -> "Showing toast: " + messageToToast);
|
||||||
Toast.makeText(mContext, messageToToast, toastDuration).show();
|
Toast.makeText(context, messageToToast, toastDuration).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isLandscapeOrientation() {
|
public static boolean isLandscapeOrientation() {
|
||||||
Context mContext = contextRef.get();
|
if (context == null) return false;
|
||||||
if (mContext == null) return false;
|
final int orientation = context.getResources().getConfiguration().orientation;
|
||||||
final int orientation = mContext.getResources().getConfiguration().orientation;
|
|
||||||
return orientation == Configuration.ORIENTATION_LANDSCAPE;
|
return orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -654,8 +748,7 @@ public class Utils {
|
|||||||
|
|
||||||
@SuppressLint("MissingPermission") // permission already included in YouTube
|
@SuppressLint("MissingPermission") // permission already included in YouTube
|
||||||
public static NetworkType getNetworkType() {
|
public static NetworkType getNetworkType() {
|
||||||
Context mContext = contextRef.get();
|
if (context == null || !(context.getSystemService(Context.CONNECTIVITY_SERVICE) instanceof ConnectivityManager cm))
|
||||||
if (mContext == null || !(mContext.getSystemService(Context.CONNECTIVITY_SERVICE) instanceof ConnectivityManager cm))
|
|
||||||
return NetworkType.NONE;
|
return NetworkType.NONE;
|
||||||
|
|
||||||
final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
|
final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
|
||||||
@ -744,14 +837,14 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Regex punctuationRegex = new Regex("\\p{P}+");
|
private static final Pattern punctuationPattern = Pattern.compile("\\p{P}+");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strips all punctuation and converts to lower case. A null parameter returns an empty string.
|
* Strips all punctuation and converts to lower case. A null parameter returns an empty string.
|
||||||
*/
|
*/
|
||||||
public static String removePunctuationConvertToLowercase(@Nullable CharSequence original) {
|
public static String removePunctuationConvertToLowercase(@Nullable CharSequence original) {
|
||||||
if (original == null) return "";
|
if (original == null) return "";
|
||||||
return punctuationRegex.replace(original, "").toLowerCase();
|
return punctuationPattern.matcher(original).replaceAll("").toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -762,7 +855,6 @@ public class Utils {
|
|||||||
* If a preference has no key or no {@link Sort} suffix,
|
* If a preference has no key or no {@link Sort} suffix,
|
||||||
* then the preferences are left unsorted.
|
* then the preferences are left unsorted.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static void sortPreferenceGroups(@NonNull PreferenceGroup group) {
|
public static void sortPreferenceGroups(@NonNull PreferenceGroup group) {
|
||||||
Sort groupSort = Sort.fromKey(group.getKey(), Sort.UNSORTED);
|
Sort groupSort = Sort.fromKey(group.getKey(), Sort.UNSORTED);
|
||||||
SortedMap<String, Preference> preferences = new TreeMap<>();
|
SortedMap<String, Preference> preferences = new TreeMap<>();
|
||||||
@ -771,8 +863,8 @@ public class Utils {
|
|||||||
Preference preference = group.getPreference(i);
|
Preference preference = group.getPreference(i);
|
||||||
|
|
||||||
final Sort preferenceSort;
|
final Sort preferenceSort;
|
||||||
if (preference instanceof PreferenceGroup preferenceGroup) {
|
if (preference instanceof PreferenceGroup subGroup) {
|
||||||
sortPreferenceGroups(preferenceGroup);
|
sortPreferenceGroups(subGroup);
|
||||||
preferenceSort = groupSort; // Sort value for groups is for it's content, not itself.
|
preferenceSort = groupSort; // Sort value for groups is for it's content, not itself.
|
||||||
} else {
|
} else {
|
||||||
// Allow individual preferences to set a key sorting.
|
// Allow individual preferences to set a key sorting.
|
||||||
@ -782,13 +874,16 @@ public class Utils {
|
|||||||
|
|
||||||
final String sortValue;
|
final String sortValue;
|
||||||
switch (preferenceSort) {
|
switch (preferenceSort) {
|
||||||
case BY_TITLE ->
|
case BY_TITLE:
|
||||||
sortValue = removePunctuationConvertToLowercase(preference.getTitle());
|
sortValue = removePunctuationConvertToLowercase(preference.getTitle());
|
||||||
case BY_KEY -> sortValue = preference.getKey();
|
break;
|
||||||
case UNSORTED -> {
|
case BY_KEY:
|
||||||
|
sortValue = preference.getKey();
|
||||||
|
break;
|
||||||
|
case UNSORTED:
|
||||||
continue; // Keep original sorting.
|
continue; // Keep original sorting.
|
||||||
}
|
default:
|
||||||
default -> throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
preferences.put(sortValue, preference);
|
preferences.put(sortValue, preference);
|
||||||
@ -798,7 +893,7 @@ public class Utils {
|
|||||||
for (Preference pref : preferences.values()) {
|
for (Preference pref : preferences.values()) {
|
||||||
int order = index++;
|
int order = index++;
|
||||||
|
|
||||||
// If the preference is a PreferenceScreen or is an intent preference, move to the top.
|
// Move any screens, intents, and the one off About preference to the top.
|
||||||
if (pref instanceof PreferenceScreen || pref.getIntent() != null) {
|
if (pref instanceof PreferenceScreen || pref.getIntent() != null) {
|
||||||
// Arbitrary high number.
|
// Arbitrary high number.
|
||||||
order -= 1000;
|
order -= 1000;
|
||||||
@ -807,4 +902,32 @@ public class Utils {
|
|||||||
pref.setOrder(order);
|
pref.setOrder(order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set all preferences to multiline titles if the device is not using an English variant.
|
||||||
|
* The English strings are heavily scrutinized and all titles fit on screen
|
||||||
|
* except 2 or 3 preference strings and those do not affect readability.
|
||||||
|
* <p>
|
||||||
|
* Allowing multiline for those 2 or 3 English preferences looks weird and out of place,
|
||||||
|
* and visually it looks better to clip the text and keep all titles 1 line.
|
||||||
|
*/
|
||||||
|
public static void setPreferenceTitlesToMultiLineIfNeeded(PreferenceGroup group) {
|
||||||
|
if (!isSDKAbove(26)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String revancedLocale = Utils.getContext().getResources().getConfiguration().locale.getLanguage();
|
||||||
|
if (revancedLocale.equals(Locale.ENGLISH.getLanguage())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, prefCount = group.getPreferenceCount(); i < prefCount; i++) {
|
||||||
|
Preference pref = group.getPreference(i);
|
||||||
|
pref.setSingleLineTitle(false);
|
||||||
|
|
||||||
|
if (pref instanceof PreferenceGroup subGroup) {
|
||||||
|
setPreferenceTitlesToMultiLineIfNeeded(subGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -189,14 +189,13 @@ public final class AlternativeThumbnailsPatch {
|
|||||||
// Unknown tab, treat as the home tab;
|
// Unknown tab, treat as the home tab;
|
||||||
return homeOption;
|
return homeOption;
|
||||||
}
|
}
|
||||||
if (selectedNavButton == NavigationButton.HOME) {
|
|
||||||
return homeOption;
|
return switch (selectedNavButton) {
|
||||||
}
|
case SUBSCRIPTIONS, NOTIFICATIONS -> subscriptionsOption;
|
||||||
if (selectedNavButton == NavigationButton.SUBSCRIPTIONS || selectedNavButton == NavigationButton.NOTIFICATIONS) {
|
case LIBRARY -> libraryOption;
|
||||||
return subscriptionsOption;
|
// Home or explore tab.
|
||||||
}
|
default -> homeOption;
|
||||||
// A library tab variant is active.
|
};
|
||||||
return libraryOption;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,12 +7,15 @@ import app.revanced.extension.shared.patches.components.ByteArrayFilterGroupList
|
|||||||
import app.revanced.extension.shared.patches.components.Filter;
|
import app.revanced.extension.shared.patches.components.Filter;
|
||||||
import app.revanced.extension.shared.patches.components.StringFilterGroup;
|
import app.revanced.extension.shared.patches.components.StringFilterGroup;
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
import app.revanced.extension.youtube.shared.EngagementPanel;
|
||||||
|
import app.revanced.extension.youtube.shared.RootView;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class DescriptionsFilter extends Filter {
|
public final class DescriptionsFilter extends Filter {
|
||||||
private final ByteArrayFilterGroupList macroMarkerShelfGroupList = new ByteArrayFilterGroupList();
|
private final ByteArrayFilterGroupList macroMarkerShelfGroupList = new ByteArrayFilterGroupList();
|
||||||
|
|
||||||
private final StringFilterGroup howThisWasMadeSection;
|
private final StringFilterGroup howThisWasMadeSection;
|
||||||
|
private final StringFilterGroup horizontalShelf;
|
||||||
private final StringFilterGroup infoCardsSection;
|
private final StringFilterGroup infoCardsSection;
|
||||||
private final StringFilterGroup macroMarkerShelf;
|
private final StringFilterGroup macroMarkerShelf;
|
||||||
private final StringFilterGroup shoppingLinks;
|
private final StringFilterGroup shoppingLinks;
|
||||||
@ -54,6 +57,13 @@ public final class DescriptionsFilter extends Filter {
|
|||||||
"how_this_was_made_section.eml"
|
"how_this_was_made_section.eml"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// In the latest YouTube, the Attribute section has the same path as the Carousel shelf.
|
||||||
|
// To hide only the Attribute section, check if the Description panel is open.
|
||||||
|
horizontalShelf = new StringFilterGroup(
|
||||||
|
Settings.HIDE_ATTRIBUTES_SECTION,
|
||||||
|
"horizontal_shelf.eml"
|
||||||
|
);
|
||||||
|
|
||||||
infoCardsSection = new StringFilterGroup(
|
infoCardsSection = new StringFilterGroup(
|
||||||
Settings.HIDE_INFO_CARDS_SECTION,
|
Settings.HIDE_INFO_CARDS_SECTION,
|
||||||
"infocards_section.eml"
|
"infocards_section.eml"
|
||||||
@ -72,6 +82,7 @@ public final class DescriptionsFilter extends Filter {
|
|||||||
|
|
||||||
addPathCallbacks(
|
addPathCallbacks(
|
||||||
howThisWasMadeSection,
|
howThisWasMadeSection,
|
||||||
|
horizontalShelf,
|
||||||
infoCardsSection,
|
infoCardsSection,
|
||||||
macroMarkerShelf,
|
macroMarkerShelf,
|
||||||
shoppingLinks
|
shoppingLinks
|
||||||
@ -104,6 +115,16 @@ public final class DescriptionsFilter extends Filter {
|
|||||||
if (!macroMarkerShelfGroupList.check(protobufBufferArray).isFiltered()) {
|
if (!macroMarkerShelfGroupList.check(protobufBufferArray).isFiltered()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
} else if (matchedGroup == horizontalShelf) {
|
||||||
|
if (contentIndex != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!RootView.isPlayerActive()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!EngagementPanel.isDescription()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.isFiltered(path, identifier, allValue, protobufBufferArray, matchedGroup, contentType, contentIndex);
|
return super.isFiltered(path, identifier, allValue, protobufBufferArray, matchedGroup, contentType, contentIndex);
|
||||||
|
@ -556,14 +556,13 @@ public final class KeywordContentFilter extends Filter {
|
|||||||
if (selectedNavButton == null) {
|
if (selectedNavButton == null) {
|
||||||
return hideHome; // Unknown tab, treat the same as home.
|
return hideHome; // Unknown tab, treat the same as home.
|
||||||
}
|
}
|
||||||
if (selectedNavButton == NavigationButton.HOME) {
|
|
||||||
return hideHome;
|
return switch (selectedNavButton) {
|
||||||
}
|
case HOME, EXPLORE -> hideHome;
|
||||||
if (selectedNavButton == NavigationButton.SUBSCRIPTIONS) {
|
case SUBSCRIPTIONS -> hideSubscriptions;
|
||||||
return hideSubscriptions;
|
// User is in the Library or notifications.
|
||||||
}
|
default -> false;
|
||||||
// User is in the Library or Notifications tab.
|
};
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateStats(boolean videoWasHidden, @Nullable String keyword) {
|
private void updateStats(boolean videoWasHidden, @Nullable String keyword) {
|
||||||
|
@ -0,0 +1,151 @@
|
|||||||
|
package app.revanced.extension.youtube.patches.general;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.FALSE;
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
import static app.revanced.extension.youtube.shared.NavigationBar.NavigationButton;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
|
import app.revanced.extension.shared.utils.PackageUtils;
|
||||||
|
import app.revanced.extension.youtube.settings.Settings;
|
||||||
|
import app.revanced.extension.youtube.shared.PlayerType;
|
||||||
|
import app.revanced.extension.youtube.shared.RootView;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class ChangeFormFactorPatch {
|
||||||
|
|
||||||
|
public enum FormFactor {
|
||||||
|
/**
|
||||||
|
* Unmodified, and same as un-patched.
|
||||||
|
*/
|
||||||
|
DEFAULT(null, null, null),
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* Some changes include:
|
||||||
|
* - Explore tab is present.
|
||||||
|
* - watch history is missing.
|
||||||
|
* - feed thumbnails fade in.
|
||||||
|
*/
|
||||||
|
UNKNOWN(0, null, null),
|
||||||
|
SMALL(1, null, TRUE),
|
||||||
|
SMALL_WIDTH_DP(1, 480, TRUE),
|
||||||
|
LARGE(2, null, FALSE),
|
||||||
|
LARGE_WIDTH_DP(2, 600, FALSE),
|
||||||
|
/**
|
||||||
|
* Cars with 'Google built-in'.
|
||||||
|
* Layout seems identical to {@link #UNKNOWN}
|
||||||
|
* even when using an Android Automotive device.
|
||||||
|
*/
|
||||||
|
AUTOMOTIVE(3, null, null),
|
||||||
|
WEARABLE(4, null, null);
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
final Integer formFactorType;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
final Integer widthDp;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
final Boolean setMinimumDp;
|
||||||
|
|
||||||
|
|
||||||
|
FormFactor(@Nullable Integer formFactorType, @Nullable Integer widthDp, @Nullable Boolean setMinimumDp) {
|
||||||
|
this.formFactorType = formFactorType;
|
||||||
|
this.widthDp = widthDp;
|
||||||
|
this.setMinimumDp = setMinimumDp;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean setMinimumDp() {
|
||||||
|
return BooleanUtils.isTrue(setMinimumDp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final FormFactor FORM_FACTOR = Settings.CHANGE_FORM_FACTOR.get();
|
||||||
|
@Nullable
|
||||||
|
private static final Integer FORM_FACTOR_TYPE = FORM_FACTOR.formFactorType;
|
||||||
|
private static final boolean USING_AUTOMOTIVE_TYPE = Objects.requireNonNull(
|
||||||
|
FormFactor.AUTOMOTIVE.formFactorType).equals(FORM_FACTOR_TYPE);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static int getFormFactor(int original) {
|
||||||
|
if (FORM_FACTOR_TYPE == null) return original;
|
||||||
|
|
||||||
|
if (USING_AUTOMOTIVE_TYPE) {
|
||||||
|
// Do not change if the player is opening or is opened,
|
||||||
|
// otherwise the video description cannot be opened.
|
||||||
|
PlayerType current = PlayerType.getCurrent();
|
||||||
|
if (current.isMaximizedOrFullscreen() || current == PlayerType.WATCH_WHILE_SLIDING_MINIMIZED_MAXIMIZED) {
|
||||||
|
Logger.printDebug(() -> "Using original form factor for player");
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
if (!RootView.isSearchBarActive()) {
|
||||||
|
// Automotive type shows error 400 when opening a channel page and using some explore tab.
|
||||||
|
// This is a bug in unpatched YouTube that occurs on actual Android Automotive devices.
|
||||||
|
// Work around the issue by using the original form factor if not in search and the
|
||||||
|
// navigation back button is present.
|
||||||
|
if (RootView.isBackButtonVisible()) {
|
||||||
|
Logger.printDebug(() -> "Using original form factor, as back button is visible without search present");
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not change library tab otherwise watch history is hidden.
|
||||||
|
// Do this check last since the current navigation button is required.
|
||||||
|
if (NavigationButton.getSelectedNavigationButton() == NavigationButton.LIBRARY) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FORM_FACTOR_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static int getWidthDp(int original) {
|
||||||
|
if (FORM_FACTOR_TYPE == null) return original;
|
||||||
|
Integer widthDp = FORM_FACTOR.widthDp;
|
||||||
|
if (widthDp == null) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
final int smallestScreenWidthDp = PackageUtils.getSmallestScreenWidthDp();
|
||||||
|
if (smallestScreenWidthDp == 0) {
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
return FORM_FACTOR.setMinimumDp()
|
||||||
|
? Math.min(smallestScreenWidthDp, widthDp)
|
||||||
|
: Math.max(smallestScreenWidthDp, widthDp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean phoneLayoutEnabled() {
|
||||||
|
return Objects.equals(FORM_FACTOR.formFactorType, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean tabletLayoutEnabled() {
|
||||||
|
return Objects.equals(FORM_FACTOR.formFactorType, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void navigationTabCreated(NavigationButton button, View tabView) {
|
||||||
|
// On first startup of the app the navigation buttons are fetched and updated.
|
||||||
|
// If the user immediately opens the 'You' or opens a video, then the call to
|
||||||
|
// update the navigtation buttons will use the non automotive form factor
|
||||||
|
// and the explore tab is missing.
|
||||||
|
// Fixing this is not so simple because of the concurrent calls for the player and You tab.
|
||||||
|
// For now, always hide the explore tab.
|
||||||
|
if (USING_AUTOMOTIVE_TYPE && button == NavigationButton.EXPLORE) {
|
||||||
|
tabView.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -478,6 +478,10 @@ public class GeneralPatch {
|
|||||||
return Settings.HIDE_SEARCH_TERM_THUMBNAIL.get();
|
return Settings.HIDE_SEARCH_TERM_THUMBNAIL.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean hideSearchTermThumbnail(boolean original) {
|
||||||
|
return !hideSearchTermThumbnail() && original;
|
||||||
|
}
|
||||||
|
|
||||||
private static final boolean hideImageSearchButton = Settings.HIDE_IMAGE_SEARCH_BUTTON.get();
|
private static final boolean hideImageSearchButton = Settings.HIDE_IMAGE_SEARCH_BUTTON.get();
|
||||||
private static final boolean hideVoiceSearchButton = Settings.HIDE_VOICE_SEARCH_BUTTON.get();
|
private static final boolean hideVoiceSearchButton = Settings.HIDE_VOICE_SEARCH_BUTTON.get();
|
||||||
|
|
||||||
|
@ -1,79 +0,0 @@
|
|||||||
package app.revanced.extension.youtube.patches.general;
|
|
||||||
|
|
||||||
import static java.lang.Boolean.FALSE;
|
|
||||||
import static java.lang.Boolean.TRUE;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import app.revanced.extension.shared.utils.PackageUtils;
|
|
||||||
import app.revanced.extension.youtube.settings.Settings;
|
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
|
||||||
public final class LayoutSwitchPatch {
|
|
||||||
|
|
||||||
public enum FormFactor {
|
|
||||||
/**
|
|
||||||
* Unmodified type, and same as un-patched.
|
|
||||||
*/
|
|
||||||
ORIGINAL(null, null, null),
|
|
||||||
SMALL_FORM_FACTOR(1, null, TRUE),
|
|
||||||
SMALL_FORM_FACTOR_WIDTH_DP(1, 480, TRUE),
|
|
||||||
LARGE_FORM_FACTOR(2, null, FALSE),
|
|
||||||
LARGE_FORM_FACTOR_WIDTH_DP(2, 600, FALSE);
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
final Integer formFactorType;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
final Integer widthDp;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
final Boolean setMinimumDp;
|
|
||||||
|
|
||||||
FormFactor(@Nullable Integer formFactorType, @Nullable Integer widthDp, @Nullable Boolean setMinimumDp) {
|
|
||||||
this.formFactorType = formFactorType;
|
|
||||||
this.widthDp = widthDp;
|
|
||||||
this.setMinimumDp = setMinimumDp;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean setMinimumDp() {
|
|
||||||
return BooleanUtils.isTrue(setMinimumDp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final FormFactor FORM_FACTOR = Settings.CHANGE_LAYOUT.get();
|
|
||||||
|
|
||||||
public static int getFormFactor(int original) {
|
|
||||||
Integer formFactorType = FORM_FACTOR.formFactorType;
|
|
||||||
return formFactorType == null
|
|
||||||
? original
|
|
||||||
: formFactorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getWidthDp(int original) {
|
|
||||||
Integer widthDp = FORM_FACTOR.widthDp;
|
|
||||||
if (widthDp == null) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
final int smallestScreenWidthDp = PackageUtils.getSmallestScreenWidthDp();
|
|
||||||
if (smallestScreenWidthDp == 0) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
return FORM_FACTOR.setMinimumDp()
|
|
||||||
? Math.min(smallestScreenWidthDp, widthDp)
|
|
||||||
: Math.max(smallestScreenWidthDp, widthDp);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean phoneLayoutEnabled() {
|
|
||||||
return Objects.equals(FORM_FACTOR.formFactorType, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean tabletLayoutEnabled() {
|
|
||||||
return Objects.equals(FORM_FACTOR.formFactorType, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -25,8 +25,11 @@ import app.revanced.extension.shared.utils.Logger;
|
|||||||
import app.revanced.extension.shared.utils.Utils;
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
|
||||||
public abstract class BottomControlButton {
|
public abstract class BottomControlButton {
|
||||||
|
@Nullable
|
||||||
private static final Animation fadeIn;
|
private static final Animation fadeIn;
|
||||||
|
@Nullable
|
||||||
private static final Animation fadeOut;
|
private static final Animation fadeOut;
|
||||||
|
@Nullable
|
||||||
private static final Animation fadeOutImmediate;
|
private static final Animation fadeOutImmediate;
|
||||||
|
|
||||||
private final ColorFilter cf =
|
private final ColorFilter cf =
|
||||||
@ -40,29 +43,35 @@ public abstract class BottomControlButton {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
fadeIn = getAnimation("fade_in");
|
fadeIn = getAnimation("fade_in");
|
||||||
|
if (fadeIn != null) {
|
||||||
// android.R.integer.config_shortAnimTime, 200
|
// android.R.integer.config_shortAnimTime, 200
|
||||||
fadeIn.setDuration(getInteger("fade_duration_fast"));
|
fadeIn.setDuration(getInteger("fade_duration_fast"));
|
||||||
|
}
|
||||||
|
|
||||||
fadeOut = getAnimation("fade_out");
|
fadeOut = getAnimation("fade_out");
|
||||||
|
if (fadeOut != null) {
|
||||||
// android.R.integer.config_mediumAnimTime, 400
|
// android.R.integer.config_mediumAnimTime, 400
|
||||||
fadeOut.setDuration(getInteger("fade_overlay_fade_duration"));
|
fadeOut.setDuration(getInteger("fade_overlay_fade_duration"));
|
||||||
|
}
|
||||||
|
|
||||||
fadeOutImmediate = getAnimation("abc_fade_out");
|
fadeOutImmediate = getAnimation("abc_fade_out");
|
||||||
|
if (fadeOutImmediate != null) {
|
||||||
// android.R.integer.config_shortAnimTime, 200
|
// android.R.integer.config_shortAnimTime, 200
|
||||||
fadeOutImmediate.setDuration(getInteger("fade_duration_fast"));
|
fadeOutImmediate.setDuration(getInteger("fade_duration_fast"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@Nullable
|
||||||
public static Animation getButtonFadeIn() {
|
public static Animation getButtonFadeIn() {
|
||||||
return fadeIn;
|
return fadeIn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Nullable
|
||||||
public static Animation getButtonFadeOut() {
|
public static Animation getButtonFadeOut() {
|
||||||
return fadeOut;
|
return fadeOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@Nullable
|
||||||
public static Animation getButtonFadeOutImmediate() {
|
public static Animation getButtonFadeOutImmediate() {
|
||||||
return fadeOutImmediate;
|
return fadeOutImmediate;
|
||||||
}
|
}
|
||||||
@ -153,11 +162,15 @@ public abstract class BottomControlButton {
|
|||||||
imageView.clearAnimation();
|
imageView.clearAnimation();
|
||||||
if (visible && setting.get()) {
|
if (visible && setting.get()) {
|
||||||
imageView.setVisibility(View.VISIBLE);
|
imageView.setVisibility(View.VISIBLE);
|
||||||
if (animation) imageView.startAnimation(fadeIn);
|
if (animation && fadeIn != null) {
|
||||||
|
imageView.startAnimation(fadeIn);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (imageView.getVisibility() == View.VISIBLE) {
|
if (imageView.getVisibility() == View.VISIBLE) {
|
||||||
if (animation) imageView.startAnimation(fadeOut);
|
if (animation && fadeOut != null) {
|
||||||
|
imageView.startAnimation(fadeOut);
|
||||||
|
}
|
||||||
imageView.setVisibility(View.GONE);
|
imageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,7 +181,9 @@ public abstract class BottomControlButton {
|
|||||||
if (!setting.get()) return;
|
if (!setting.get()) return;
|
||||||
|
|
||||||
imageView.clearAnimation();
|
imageView.clearAnimation();
|
||||||
|
if (fadeOutImmediate != null) {
|
||||||
imageView.startAnimation(fadeOutImmediate);
|
imageView.startAnimation(fadeOutImmediate);
|
||||||
|
}
|
||||||
imageView.setVisibility(View.GONE);
|
imageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +147,7 @@ class ActionButtonRequest private constructor(
|
|||||||
} catch (ex: IOException) {
|
} catch (ex: IOException) {
|
||||||
handleConnectionError("Network error", ex)
|
handleConnectionError("Network error", ex)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
Logger.printException({ "sendApplicationRequest failed" }, ex)
|
Logger.printException({ "sendRequest failed" }, ex)
|
||||||
} finally {
|
} finally {
|
||||||
Logger.printDebug { "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms" }
|
Logger.printDebug { "video: " + videoId + " took: " + (System.currentTimeMillis() - startTime) + "ms" }
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package app.revanced.extension.youtube.patches.utils;
|
package app.revanced.extension.youtube.patches.utils;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
|
||||||
public class PatchStatus {
|
public class PatchStatus {
|
||||||
|
|
||||||
public static boolean ImageSearchButton() {
|
public static boolean ImageSearchButton() {
|
||||||
@ -7,6 +9,11 @@ public class PatchStatus {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean OldSplashAnimation() {
|
||||||
|
// Replace this with true if the Restore old splash animation (Custom branding icon) succeeds
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean PlayerButtons() {
|
public static boolean PlayerButtons() {
|
||||||
// Replace this with true if the Hide player buttons patch succeeds
|
// Replace this with true if the Hide player buttons patch succeeds
|
||||||
return false;
|
return false;
|
||||||
@ -22,6 +29,12 @@ public class PatchStatus {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean SplashAnimation() {
|
||||||
|
// If 'Restore old splash animation' is included and device is running Android 12+,
|
||||||
|
// YouTube TV splash animations will be disabled by default.
|
||||||
|
return OldSplashAnimation() && Utils.isSDKAbove(31);
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean SponsorBlock() {
|
public static boolean SponsorBlock() {
|
||||||
// Replace this with true if the SponsorBlock patch succeeds
|
// Replace this with true if the SponsorBlock patch succeeds
|
||||||
return false;
|
return false;
|
||||||
|
@ -3,6 +3,7 @@ package app.revanced.extension.youtube.returnyoutubedislike;
|
|||||||
import static app.revanced.extension.shared.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
import static app.revanced.extension.shared.returnyoutubedislike.ReturnYouTubeDislike.Vote;
|
||||||
import static app.revanced.extension.shared.utils.StringRef.str;
|
import static app.revanced.extension.shared.utils.StringRef.str;
|
||||||
import static app.revanced.extension.shared.utils.Utils.isSDKAbove;
|
import static app.revanced.extension.shared.utils.Utils.isSDKAbove;
|
||||||
|
import static app.revanced.extension.shared.utils.Utils.newSpanUsingStylingOfAnotherSpan;
|
||||||
import static app.revanced.extension.youtube.utils.ExtendedUtils.isSpoofingToLessThan;
|
import static app.revanced.extension.youtube.utils.ExtendedUtils.isSpoofingToLessThan;
|
||||||
|
|
||||||
import android.content.res.Resources;
|
import android.content.res.Resources;
|
||||||
@ -336,20 +337,6 @@ public class ReturnYouTubeDislike {
|
|||||||
: formatDislikeCount(voteData.getDislikeCount()));
|
: formatDislikeCount(voteData.getDislikeCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SpannableString newSpanUsingStylingOfAnotherSpan(@NonNull Spanned sourceStyle, @NonNull CharSequence newSpanText) {
|
|
||||||
if (sourceStyle == newSpanText && sourceStyle instanceof SpannableString spannableString) {
|
|
||||||
return spannableString; // Nothing to do.
|
|
||||||
}
|
|
||||||
|
|
||||||
SpannableString destination = new SpannableString(newSpanText);
|
|
||||||
Object[] spans = sourceStyle.getSpans(0, sourceStyle.length(), Object.class);
|
|
||||||
for (Object span : spans) {
|
|
||||||
destination.setSpan(span, 0, destination.length(), sourceStyle.getSpanFlags(span));
|
|
||||||
}
|
|
||||||
|
|
||||||
return destination;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String formatDislikeCount(long dislikeCount) {
|
private static String formatDislikeCount(long dislikeCount) {
|
||||||
if (isSDKAbove(24)) {
|
if (isSDKAbove(24)) {
|
||||||
synchronized (ReturnYouTubeDislike.class) { // Number formatter is not thread safe.
|
synchronized (ReturnYouTubeDislike.class) { // Number formatter is not thread safe.
|
||||||
|
@ -32,9 +32,9 @@ import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeT
|
|||||||
import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeThumbnailsPatch.StillImagesAvailability;
|
import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeThumbnailsPatch.StillImagesAvailability;
|
||||||
import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeThumbnailsPatch.ThumbnailOption;
|
import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeThumbnailsPatch.ThumbnailOption;
|
||||||
import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeThumbnailsPatch.ThumbnailStillTime;
|
import app.revanced.extension.youtube.patches.alternativethumbnails.AlternativeThumbnailsPatch.ThumbnailStillTime;
|
||||||
|
import app.revanced.extension.youtube.patches.general.ChangeFormFactorPatch.FormFactor;
|
||||||
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch;
|
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch;
|
||||||
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch.StartPage;
|
import app.revanced.extension.youtube.patches.general.ChangeStartPagePatch.StartPage;
|
||||||
import app.revanced.extension.youtube.patches.general.LayoutSwitchPatch.FormFactor;
|
|
||||||
import app.revanced.extension.youtube.patches.general.YouTubeMusicActionsPatch;
|
import app.revanced.extension.youtube.patches.general.YouTubeMusicActionsPatch;
|
||||||
import app.revanced.extension.youtube.patches.player.ExitFullscreenPatch.FullscreenMode;
|
import app.revanced.extension.youtube.patches.player.ExitFullscreenPatch.FullscreenMode;
|
||||||
import app.revanced.extension.youtube.patches.player.MiniplayerPatch;
|
import app.revanced.extension.youtube.patches.player.MiniplayerPatch;
|
||||||
@ -147,14 +147,14 @@ public class Settings extends BaseSettings {
|
|||||||
public static final BooleanSetting CHANGE_START_PAGE_TYPE = new BooleanSetting("revanced_change_start_page_type", FALSE, true,
|
public static final BooleanSetting CHANGE_START_PAGE_TYPE = new BooleanSetting("revanced_change_start_page_type", FALSE, true,
|
||||||
new ChangeStartPagePatch.ChangeStartPageTypeAvailability());
|
new ChangeStartPagePatch.ChangeStartPageTypeAvailability());
|
||||||
public static final BooleanSetting DISABLE_AUTO_AUDIO_TRACKS = new BooleanSetting("revanced_disable_auto_audio_tracks", FALSE);
|
public static final BooleanSetting DISABLE_AUTO_AUDIO_TRACKS = new BooleanSetting("revanced_disable_auto_audio_tracks", FALSE);
|
||||||
public static final BooleanSetting DISABLE_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_splash_animation", FALSE, true);
|
public static final BooleanSetting DISABLE_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_splash_animation", PatchStatus.SplashAnimation(), true);
|
||||||
public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", TRUE, true);
|
public static final BooleanSetting DISABLE_TRANSLUCENT_STATUS_BAR = new BooleanSetting("revanced_disable_translucent_status_bar", TRUE, true);
|
||||||
public static final BooleanSetting ENABLE_GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_enable_gradient_loading_screen", FALSE, true);
|
public static final BooleanSetting ENABLE_GRADIENT_LOADING_SCREEN = new BooleanSetting("revanced_enable_gradient_loading_screen", FALSE, true);
|
||||||
public static final BooleanSetting HIDE_FLOATING_MICROPHONE = new BooleanSetting("revanced_hide_floating_microphone", TRUE, true);
|
public static final BooleanSetting HIDE_FLOATING_MICROPHONE = new BooleanSetting("revanced_hide_floating_microphone", TRUE, true);
|
||||||
public static final BooleanSetting HIDE_GRAY_SEPARATOR = new BooleanSetting("revanced_hide_gray_separator", TRUE);
|
public static final BooleanSetting HIDE_GRAY_SEPARATOR = new BooleanSetting("revanced_hide_gray_separator", TRUE);
|
||||||
public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG = new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE);
|
public static final BooleanSetting REMOVE_VIEWER_DISCRETION_DIALOG = new BooleanSetting("revanced_remove_viewer_discretion_dialog", FALSE);
|
||||||
|
|
||||||
public static final EnumSetting<FormFactor> CHANGE_LAYOUT = new EnumSetting<>("revanced_change_layout", FormFactor.ORIGINAL, true);
|
public static final EnumSetting<FormFactor> CHANGE_FORM_FACTOR = new EnumSetting<>("revanced_change_form_factor", FormFactor.DEFAULT, true, "revanced_change_form_factor_user_dialog_message");
|
||||||
public static final BooleanSetting CHANGE_LIVE_RING_CLICK_ACTION = new BooleanSetting("revanced_change_live_ring_click_action", FALSE, true);
|
public static final BooleanSetting CHANGE_LIVE_RING_CLICK_ACTION = new BooleanSetting("revanced_change_live_ring_click_action", FALSE, true);
|
||||||
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", false, true, "revanced_spoof_app_version_user_dialog_message");
|
public static final BooleanSetting SPOOF_APP_VERSION = new BooleanSetting("revanced_spoof_app_version", false, true, "revanced_spoof_app_version_user_dialog_message");
|
||||||
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", PatchStatus.SpoofAppVersionDefaultString(), true, parent(SPOOF_APP_VERSION));
|
public static final StringSetting SPOOF_APP_VERSION_TARGET = new StringSetting("revanced_spoof_app_version_target", PatchStatus.SpoofAppVersionDefaultString(), true, parent(SPOOF_APP_VERSION));
|
||||||
|
@ -75,7 +75,7 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
|
|||||||
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
|
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
|
||||||
try {
|
try {
|
||||||
if (str == null) return;
|
if (str == null) return;
|
||||||
Setting<?> setting = Setting.getSettingFromPath(str);
|
Setting<?> setting = Setting.getSettingFromPath(Objects.requireNonNull(str));
|
||||||
|
|
||||||
if (setting == null) return;
|
if (setting == null) return;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import android.preference.Preference;
|
|||||||
import android.preference.SwitchPreference;
|
import android.preference.SwitchPreference;
|
||||||
|
|
||||||
import app.revanced.extension.shared.settings.Setting;
|
import app.revanced.extension.shared.settings.Setting;
|
||||||
import app.revanced.extension.youtube.patches.general.LayoutSwitchPatch;
|
import app.revanced.extension.youtube.patches.general.ChangeFormFactorPatch;
|
||||||
import app.revanced.extension.youtube.patches.utils.PatchStatus;
|
import app.revanced.extension.youtube.patches.utils.PatchStatus;
|
||||||
import app.revanced.extension.youtube.patches.utils.ReturnYouTubeDislikePatch;
|
import app.revanced.extension.youtube.patches.utils.ReturnYouTubeDislikePatch;
|
||||||
import app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike;
|
import app.revanced.extension.youtube.returnyoutubedislike.ReturnYouTubeDislike;
|
||||||
@ -82,7 +82,7 @@ public class ReVancedSettingsPreference extends ReVancedPreferenceFragment {
|
|||||||
*/
|
*/
|
||||||
private static void TabletLayoutLinks() {
|
private static void TabletLayoutLinks() {
|
||||||
final boolean isTablet = ExtendedUtils.isTablet() &&
|
final boolean isTablet = ExtendedUtils.isTablet() &&
|
||||||
!LayoutSwitchPatch.phoneLayoutEnabled();
|
!ChangeFormFactorPatch.phoneLayoutEnabled();
|
||||||
|
|
||||||
enableDisablePreferences(
|
enableDisablePreferences(
|
||||||
isTablet,
|
isTablet,
|
||||||
|
@ -6,7 +6,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||||||
|
|
||||||
import app.revanced.extension.shared.utils.Logger;
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings({"unused", "BooleanMethodIsAlwaysInverted"})
|
||||||
public final class EngagementPanel {
|
public final class EngagementPanel {
|
||||||
private static final AtomicReference<String> engagementPanelId = new AtomicReference<>("");
|
private static final AtomicReference<String> engagementPanelId = new AtomicReference<>("");
|
||||||
|
|
||||||
|
@ -223,6 +223,10 @@ public final class NavigationBar {
|
|||||||
* This tab will never be in a selected state, even if the create video UI is on screen.
|
* This tab will never be in a selected state, even if the create video UI is on screen.
|
||||||
*/
|
*/
|
||||||
CREATE("CREATION_TAB_LARGE", "CREATION_TAB_LARGE_CAIRO"),
|
CREATE("CREATION_TAB_LARGE", "CREATION_TAB_LARGE_CAIRO"),
|
||||||
|
/**
|
||||||
|
* Only shown to automotive layout.
|
||||||
|
*/
|
||||||
|
EXPLORE("TAB_EXPLORE"),
|
||||||
SUBSCRIPTIONS("PIVOT_SUBSCRIPTIONS", "TAB_SUBSCRIPTIONS_CAIRO"),
|
SUBSCRIPTIONS("PIVOT_SUBSCRIPTIONS", "TAB_SUBSCRIPTIONS_CAIRO"),
|
||||||
/**
|
/**
|
||||||
* Notifications tab. Only present when
|
* Notifications tab. Only present when
|
||||||
|
@ -2,9 +2,48 @@ package app.revanced.extension.youtube.shared;
|
|||||||
|
|
||||||
import static app.revanced.extension.youtube.patches.components.RelatedVideoFilter.isActionBarVisible;
|
import static app.revanced.extension.youtube.patches.components.RelatedVideoFilter.isActionBarVisible;
|
||||||
|
|
||||||
|
import android.graphics.drawable.Drawable;
|
||||||
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
|
||||||
|
import app.revanced.extension.shared.utils.Logger;
|
||||||
|
import app.revanced.extension.shared.utils.Utils;
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public final class RootView {
|
public final class RootView {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface to call obfuscated methods in AppCompat Toolbar class.
|
||||||
|
*/
|
||||||
|
public interface AppCompatToolbarPatchInterface {
|
||||||
|
Drawable patch_getToolbarIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static volatile WeakReference<AppCompatToolbarPatchInterface> toolbarResultsRef
|
||||||
|
= new WeakReference<>(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Injection point.
|
||||||
|
*/
|
||||||
|
public static void setToolbar(FrameLayout layout) {
|
||||||
|
AppCompatToolbarPatchInterface toolbar = Utils.getChildView(layout, false, (view) ->
|
||||||
|
view instanceof AppCompatToolbarPatchInterface
|
||||||
|
);
|
||||||
|
|
||||||
|
if (toolbar == null) {
|
||||||
|
Logger.printException(() -> "Could not find toolbar");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
toolbarResultsRef = new WeakReference<>(toolbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBackButtonVisible() {
|
||||||
|
AppCompatToolbarPatchInterface toolbar = toolbarResultsRef.get();
|
||||||
|
return toolbar != null && toolbar.patch_getToolbarIcon() != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return If the search bar is on screen. This includes if the player
|
* @return If the search bar is on screen. This includes if the player
|
||||||
* is on screen and the search results are behind the player (and not visible).
|
* is on screen and the search results are behind the player (and not visible).
|
||||||
|
@ -3,6 +3,7 @@ package app.revanced.extension.youtube.sponsorblock.ui;
|
|||||||
import static app.revanced.extension.shared.utils.Utils.getChildView;
|
import static app.revanced.extension.shared.utils.Utils.getChildView;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.animation.Animation;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@ -45,7 +46,10 @@ public class CreateSegmentButtonController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (animation) {
|
if (animation) {
|
||||||
imageView.startAnimation(BottomControlButton.getButtonFadeIn());
|
Animation fadeIn = BottomControlButton.getButtonFadeIn();
|
||||||
|
if (fadeIn != null) {
|
||||||
|
imageView.startAnimation(fadeIn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
imageView.setVisibility(View.VISIBLE);
|
imageView.setVisibility(View.VISIBLE);
|
||||||
return;
|
return;
|
||||||
@ -53,7 +57,10 @@ public class CreateSegmentButtonController {
|
|||||||
if (imageView.getVisibility() == View.VISIBLE) {
|
if (imageView.getVisibility() == View.VISIBLE) {
|
||||||
imageView.clearAnimation();
|
imageView.clearAnimation();
|
||||||
if (animation) {
|
if (animation) {
|
||||||
imageView.startAnimation(BottomControlButton.getButtonFadeOut());
|
Animation fadeOut = BottomControlButton.getButtonFadeOut();
|
||||||
|
if (fadeOut != null) {
|
||||||
|
imageView.startAnimation(fadeOut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
imageView.setVisibility(View.GONE);
|
imageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@ -65,7 +72,10 @@ public class CreateSegmentButtonController {
|
|||||||
if (!shouldBeShown()) return;
|
if (!shouldBeShown()) return;
|
||||||
|
|
||||||
imageView.clearAnimation();
|
imageView.clearAnimation();
|
||||||
imageView.startAnimation(BottomControlButton.getButtonFadeOutImmediate());
|
Animation fadeOutImmediate = BottomControlButton.getButtonFadeOutImmediate();
|
||||||
|
if (fadeOutImmediate != null) {
|
||||||
|
imageView.startAnimation(fadeOutImmediate);
|
||||||
|
}
|
||||||
imageView.setVisibility(View.GONE);
|
imageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import static app.revanced.extension.shared.utils.Utils.getChildView;
|
|||||||
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.videoHasSegments;
|
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.videoHasSegments;
|
||||||
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.animation.Animation;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
@ -47,7 +48,10 @@ public class VotingButtonController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (animation) {
|
if (animation) {
|
||||||
imageView.startAnimation(BottomControlButton.getButtonFadeIn());
|
Animation fadeIn = BottomControlButton.getButtonFadeIn();
|
||||||
|
if (fadeIn != null) {
|
||||||
|
imageView.startAnimation(fadeIn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
imageView.setVisibility(View.VISIBLE);
|
imageView.setVisibility(View.VISIBLE);
|
||||||
return;
|
return;
|
||||||
@ -55,7 +59,10 @@ public class VotingButtonController {
|
|||||||
if (imageView.getVisibility() == View.VISIBLE) {
|
if (imageView.getVisibility() == View.VISIBLE) {
|
||||||
imageView.clearAnimation();
|
imageView.clearAnimation();
|
||||||
if (animation) {
|
if (animation) {
|
||||||
imageView.startAnimation(BottomControlButton.getButtonFadeOut());
|
Animation fadeOut = BottomControlButton.getButtonFadeOut();
|
||||||
|
if (fadeOut != null) {
|
||||||
|
imageView.startAnimation(fadeOut);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
imageView.setVisibility(View.GONE);
|
imageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
@ -68,7 +75,10 @@ public class VotingButtonController {
|
|||||||
|
|
||||||
|
|
||||||
imageView.clearAnimation();
|
imageView.clearAnimation();
|
||||||
imageView.startAnimation(BottomControlButton.getButtonFadeOutImmediate());
|
Animation fadeOutImmediate = BottomControlButton.getButtonFadeOutImmediate();
|
||||||
|
if (fadeOutImmediate != null) {
|
||||||
|
imageView.startAnimation(fadeOutImmediate);
|
||||||
|
}
|
||||||
imageView.setVisibility(View.GONE);
|
imageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,5 +4,5 @@ org.gradle.parallel = true
|
|||||||
android.useAndroidX = true
|
android.useAndroidX = true
|
||||||
kotlin.code.style = official
|
kotlin.code.style = official
|
||||||
kotlin.jvm.target.validation.mode = IGNORE
|
kotlin.jvm.target.validation.mode = IGNORE
|
||||||
version = 5.4.2
|
version = 5.5.1
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ revanced-patcher = "21.0.0"
|
|||||||
# Tracking https://github.com/google/smali/issues/64.
|
# Tracking https://github.com/google/smali/issues/64.
|
||||||
#noinspection GradleDependency
|
#noinspection GradleDependency
|
||||||
smali = "3.0.5"
|
smali = "3.0.5"
|
||||||
gson = "2.11.0"
|
gson = "2.12.1"
|
||||||
agp = "8.2.2"
|
agp = "8.2.2"
|
||||||
annotation = "1.9.1"
|
annotation = "1.9.1"
|
||||||
lang3 = "3.17.0"
|
lang3 = "3.17.0"
|
||||||
|
164
patches.json
164
patches.json
@ -58,7 +58,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -99,7 +100,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -138,17 +140,20 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Change layout",
|
"name": "Change form factor",
|
||||||
"description": "Adds an option to change the dp in order to use a tablet or phone layout.",
|
"description": "Adds an option to change the UI appearance to a phone, tablet, or automotive device.",
|
||||||
"use": true,
|
"use": true,
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"Settings for YouTube"
|
"Settings for YouTube",
|
||||||
|
"BytecodePatch",
|
||||||
|
"BytecodePatch"
|
||||||
],
|
],
|
||||||
"compatiblePackages": {
|
"compatiblePackages": {
|
||||||
"com.google.android.youtube": [
|
"com.google.android.youtube": [
|
||||||
@ -250,7 +255,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -282,6 +288,7 @@
|
|||||||
"description": "Adds an option to set which page the app opens in instead of the homepage.",
|
"description": "Adds an option to set which page the app opens in instead of the homepage.",
|
||||||
"use": true,
|
"use": true,
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
"ResourcePatch",
|
||||||
"Settings for YouTube Music"
|
"Settings for YouTube Music"
|
||||||
],
|
],
|
||||||
"compatiblePackages": {
|
"compatiblePackages": {
|
||||||
@ -292,7 +299,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -448,7 +456,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -564,7 +573,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -676,7 +686,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -708,7 +719,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -781,7 +793,8 @@
|
|||||||
"7.06.54",
|
"7.06.54",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -802,7 +815,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -823,7 +837,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -865,7 +880,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -906,7 +922,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -969,7 +986,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1020,7 +1038,8 @@
|
|||||||
"description": "Adds an option to disable the popup that appears when taking a screenshot.",
|
"description": "Adds an option to disable the popup that appears when taking a screenshot.",
|
||||||
"use": true,
|
"use": true,
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"Settings for Reddit"
|
"Settings for Reddit",
|
||||||
|
"ResourcePatch"
|
||||||
],
|
],
|
||||||
"compatiblePackages": {
|
"compatiblePackages": {
|
||||||
"com.reddit.frontpage": [
|
"com.reddit.frontpage": [
|
||||||
@ -1067,7 +1086,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1108,7 +1128,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1169,7 +1190,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1196,7 +1218,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1264,7 +1287,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -1451,7 +1475,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1476,7 +1501,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1526,7 +1552,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1661,7 +1688,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1722,7 +1750,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1788,7 +1817,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -1956,9 +1986,11 @@
|
|||||||
"description": "Adds options to hide or change components related to the navigation bar.",
|
"description": "Adds options to hide or change components related to the navigation bar.",
|
||||||
"use": true,
|
"use": true,
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
|
"Change start page",
|
||||||
"ResourcePatch",
|
"ResourcePatch",
|
||||||
"ResourcePatch",
|
"ResourcePatch",
|
||||||
"Settings for YouTube Music"
|
"Settings for YouTube Music",
|
||||||
|
"ResourcePatch"
|
||||||
],
|
],
|
||||||
"compatiblePackages": {
|
"compatiblePackages": {
|
||||||
"com.google.android.apps.youtube.music": [
|
"com.google.android.apps.youtube.music": [
|
||||||
@ -1968,7 +2000,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2140,7 +2173,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2203,7 +2237,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2261,7 +2296,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2302,7 +2338,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2323,7 +2360,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2369,7 +2407,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2411,7 +2450,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2591,7 +2631,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -2750,7 +2791,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -2840,7 +2882,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Spoof client",
|
"name": "Spoof client",
|
||||||
"description": "Adds options to spoof the client to allow playback.",
|
"description": "Adds options to spoof the client to allow playback.",
|
||||||
"use": true,
|
"use": false,
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"Settings for YouTube Music",
|
"Settings for YouTube Music",
|
||||||
"ResourcePatch",
|
"ResourcePatch",
|
||||||
@ -2856,7 +2898,31 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"options": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Spoof player parameter",
|
||||||
|
"description": "Adds options to spoof player parameter to allow playback.",
|
||||||
|
"use": true,
|
||||||
|
"dependencies": [
|
||||||
|
"Settings for YouTube Music",
|
||||||
|
"BytecodePatch",
|
||||||
|
"BytecodePatch"
|
||||||
|
],
|
||||||
|
"compatiblePackages": {
|
||||||
|
"com.google.android.apps.youtube.music": [
|
||||||
|
"6.20.51",
|
||||||
|
"6.29.59",
|
||||||
|
"6.42.55",
|
||||||
|
"6.51.53",
|
||||||
|
"7.16.53",
|
||||||
|
"7.25.53",
|
||||||
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -3056,7 +3122,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -3106,7 +3173,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
@ -3201,7 +3269,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": [
|
"options": [
|
||||||
@ -3238,7 +3307,8 @@
|
|||||||
"6.51.53",
|
"6.51.53",
|
||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51"
|
"8.05.51",
|
||||||
|
"8.10.51"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"options": []
|
"options": []
|
||||||
|
@ -198,6 +198,10 @@ public final class app/revanced/patches/music/utils/fix/fileprovider/FileProvide
|
|||||||
public static final fun fileProviderPatch (Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun fileProviderPatch (Ljava/lang/String;Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/utils/fix/parameter/SpoofPlayerParameterPatchKt {
|
||||||
|
public static final fun getSpoofPlayerParameterPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/utils/flyoutmenu/FlyoutMenuHookPatchKt {
|
public final class app/revanced/patches/music/utils/flyoutmenu/FlyoutMenuHookPatchKt {
|
||||||
public static final fun getFlyoutMenuHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getFlyoutMenuHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
@ -288,6 +292,10 @@ public final class app/revanced/patches/music/utils/resourceid/SharedResourceIdP
|
|||||||
public static final fun getTouchOutside ()J
|
public static final fun getTouchOutside ()J
|
||||||
public static final fun getTrimSilenceSwitch ()J
|
public static final fun getTrimSilenceSwitch ()J
|
||||||
public static final fun getVarispeedUnavailableTitle ()J
|
public static final fun getVarispeedUnavailableTitle ()J
|
||||||
|
public static final fun getYtFillSamples ()J
|
||||||
|
public static final fun getYtFillYouTubeMusic ()J
|
||||||
|
public static final fun getYtOutlineSamples ()J
|
||||||
|
public static final fun getYtOutlineYouTubeMusic ()J
|
||||||
public static final fun getYtmLogo ()J
|
public static final fun getYtmLogo ()J
|
||||||
public static final fun getYtmLogoRingo2 ()J
|
public static final fun getYtmLogoRingo2 ()J
|
||||||
public static final fun isTablet ()J
|
public static final fun isTablet ()J
|
||||||
@ -331,10 +339,30 @@ public final class app/revanced/patches/music/video/playback/VideoPlaybackPatchK
|
|||||||
public static final fun getVideoPlaybackPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getVideoPlaybackPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract class app/revanced/patches/music/video/playerresponse/Hook {
|
||||||
|
public synthetic fun <init> (Ljava/lang/String;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||||
|
public fun toString ()Ljava/lang/String;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/video/playerresponse/Hook$PlayerParameter : app/revanced/patches/music/video/playerresponse/Hook {
|
||||||
|
public fun <init> (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/video/playerresponse/Hook$PlayerParameterBeforeVideoId : app/revanced/patches/music/video/playerresponse/Hook {
|
||||||
|
public fun <init> (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/video/playerresponse/Hook$VideoId : app/revanced/patches/music/video/playerresponse/Hook {
|
||||||
|
public fun <init> (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/music/video/playerresponse/Hook$VideoIdAndPlaylistId : app/revanced/patches/music/video/playerresponse/Hook {
|
||||||
|
public fun <init> (Ljava/lang/String;)V
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatchKt {
|
public final class app/revanced/patches/music/video/playerresponse/PlayerResponseMethodHookPatchKt {
|
||||||
|
public static final fun addPlayerResponseMethodHook (Lapp/revanced/patches/music/video/playerresponse/Hook;)V
|
||||||
public static final fun getPlayerResponseMethodHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getPlayerResponseMethodHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
public static final fun hookPlayerResponse (Ljava/lang/String;Z)V
|
|
||||||
public static synthetic fun hookPlayerResponse$default (Ljava/lang/String;ZILjava/lang/Object;)V
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/reddit/ad/AdsPatchKt {
|
public final class app/revanced/patches/reddit/ad/AdsPatchKt {
|
||||||
@ -424,6 +452,10 @@ public final class app/revanced/patches/reddit/utils/extension/SharedExtensionPa
|
|||||||
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getSharedExtensionPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class app/revanced/patches/reddit/utils/resourceid/SharedResourceIdPatchKt {
|
||||||
|
public static final fun getScreenShotShareBanner ()J
|
||||||
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/reddit/utils/settings/SettingsPatchKt {
|
public final class app/revanced/patches/reddit/utils/settings/SettingsPatchKt {
|
||||||
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
public static final fun getSettingsPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
|
||||||
public static final fun is_2024_26_or_greater ()Z
|
public static final fun is_2024_26_or_greater ()Z
|
||||||
@ -643,8 +675,8 @@ public final class app/revanced/patches/youtube/general/downloads/DownloadAction
|
|||||||
public static final fun getDownloadActionsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getDownloadActionsPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/general/layoutswitch/LayoutSwitchPatchKt {
|
public final class app/revanced/patches/youtube/general/formfactor/ChangeFormFactorPatchKt {
|
||||||
public static final fun getLayoutSwitchPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
public static final fun getChangeFormFactorPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/general/livering/OpenChannelOfLiveAvatarPatchKt {
|
public final class app/revanced/patches/youtube/general/livering/OpenChannelOfLiveAvatarPatchKt {
|
||||||
@ -992,6 +1024,7 @@ public final class app/revanced/patches/youtube/utils/playservice/VersionCheckPa
|
|||||||
public static final fun is_19_04_or_greater ()Z
|
public static final fun is_19_04_or_greater ()Z
|
||||||
public static final fun is_19_09_or_greater ()Z
|
public static final fun is_19_09_or_greater ()Z
|
||||||
public static final fun is_19_15_or_greater ()Z
|
public static final fun is_19_15_or_greater ()Z
|
||||||
|
public static final fun is_19_16_or_greater ()Z
|
||||||
public static final fun is_19_17_or_greater ()Z
|
public static final fun is_19_17_or_greater ()Z
|
||||||
public static final fun is_19_23_or_greater ()Z
|
public static final fun is_19_23_or_greater ()Z
|
||||||
public static final fun is_19_25_or_greater ()Z
|
public static final fun is_19_25_or_greater ()Z
|
||||||
@ -1010,6 +1043,7 @@ public final class app/revanced/patches/youtube/utils/playservice/VersionCheckPa
|
|||||||
public static final fun is_20_02_or_greater ()Z
|
public static final fun is_20_02_or_greater ()Z
|
||||||
public static final fun is_20_03_or_greater ()Z
|
public static final fun is_20_03_or_greater ()Z
|
||||||
public static final fun is_20_05_or_greater ()Z
|
public static final fun is_20_05_or_greater ()Z
|
||||||
|
public static final fun is_20_10_or_greater ()Z
|
||||||
}
|
}
|
||||||
|
|
||||||
public final class app/revanced/patches/youtube/utils/recyclerview/RecyclerViewTreeObserverPatchKt {
|
public final class app/revanced/patches/youtube/utils/recyclerview/RecyclerViewTreeObserverPatchKt {
|
||||||
@ -1122,6 +1156,7 @@ public final class app/revanced/patches/youtube/utils/resourceid/SharedResourceI
|
|||||||
public static final fun getTapBloomView ()J
|
public static final fun getTapBloomView ()J
|
||||||
public static final fun getTitleAnchor ()J
|
public static final fun getTitleAnchor ()J
|
||||||
public static final fun getToolTipContentView ()J
|
public static final fun getToolTipContentView ()J
|
||||||
|
public static final fun getToolbarContainerId ()J
|
||||||
public static final fun getTotalTime ()J
|
public static final fun getTotalTime ()J
|
||||||
public static final fun getTouchArea ()J
|
public static final fun getTouchArea ()J
|
||||||
public static final fun getVarispeedUnavailableTitle ()J
|
public static final fun getVarispeedUnavailableTitle ()J
|
||||||
|
@ -4,13 +4,17 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.music.utils.extension.Constants.GENERAL_PATH
|
import app.revanced.patches.music.utils.extension.Constants.GENERAL_PATH
|
||||||
import app.revanced.patches.music.utils.patch.PatchList.CHANGE_START_PAGE
|
import app.revanced.patches.music.utils.patch.PatchList.CHANGE_START_PAGE
|
||||||
|
import app.revanced.patches.music.utils.playservice.is_6_27_or_greater
|
||||||
|
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.music.utils.settings.CategoryType
|
import app.revanced.patches.music.utils.settings.CategoryType
|
||||||
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
|
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
|
||||||
import app.revanced.patches.music.utils.settings.addPreferenceWithIntent
|
import app.revanced.patches.music.utils.settings.addPreferenceWithIntent
|
||||||
import app.revanced.patches.music.utils.settings.settingsPatch
|
import app.revanced.patches.music.utils.settings.settingsPatch
|
||||||
|
import app.revanced.util.addEntryValues
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
@ -22,6 +26,33 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
|||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
"$GENERAL_PATH/ChangeStartPagePatch;"
|
"$GENERAL_PATH/ChangeStartPagePatch;"
|
||||||
|
|
||||||
|
private val changeStartPageResourcePatch = resourcePatch(
|
||||||
|
description = "changeStartPageResourcePatch"
|
||||||
|
) {
|
||||||
|
dependsOn(
|
||||||
|
settingsPatch,
|
||||||
|
versionCheckPatch,
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
fun appendStartPage(startPage: String) {
|
||||||
|
addEntryValues(
|
||||||
|
"revanced_change_start_page_entries",
|
||||||
|
"@string/revanced_change_start_page_entry_$startPage",
|
||||||
|
)
|
||||||
|
addEntryValues(
|
||||||
|
"revanced_change_start_page_entry_values",
|
||||||
|
startPage.uppercase(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_6_27_or_greater) {
|
||||||
|
appendStartPage("search")
|
||||||
|
}
|
||||||
|
appendStartPage("subscriptions")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val changeStartPagePatch = bytecodePatch(
|
val changeStartPagePatch = bytecodePatch(
|
||||||
CHANGE_START_PAGE.title,
|
CHANGE_START_PAGE.title,
|
||||||
@ -29,7 +60,10 @@ val changeStartPagePatch = bytecodePatch(
|
|||||||
) {
|
) {
|
||||||
compatibleWith(COMPATIBLE_PACKAGE)
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
dependsOn(settingsPatch)
|
dependsOn(
|
||||||
|
changeStartPageResourcePatch,
|
||||||
|
settingsPatch,
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@ import app.revanced.patches.music.utils.settings.addSwitchPreference
|
|||||||
import app.revanced.patches.music.utils.settings.settingsPatch
|
import app.revanced.patches.music.utils.settings.settingsPatch
|
||||||
import app.revanced.patches.music.video.information.videoIdHook
|
import app.revanced.patches.music.video.information.videoIdHook
|
||||||
import app.revanced.patches.music.video.information.videoInformationPatch
|
import app.revanced.patches.music.video.information.videoInformationPatch
|
||||||
import app.revanced.patches.music.video.playerresponse.hookPlayerResponse
|
import app.revanced.patches.music.video.playerresponse.Hook
|
||||||
|
import app.revanced.patches.music.video.playerresponse.addPlayerResponseMethodHook
|
||||||
import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch
|
import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch
|
||||||
import app.revanced.util.findMethodOrThrow
|
import app.revanced.util.findMethodOrThrow
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
@ -46,7 +47,11 @@ val albumMusicVideoPatch = bytecodePatch(
|
|||||||
|
|
||||||
// region hook player response
|
// region hook player response
|
||||||
|
|
||||||
hookPlayerResponse("$EXTENSION_CLASS_DESCRIPTOR->newPlayerResponse(Ljava/lang/String;Ljava/lang/String;I)V")
|
addPlayerResponseMethodHook(
|
||||||
|
Hook.VideoIdAndPlaylistId(
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->newPlayerResponse(Ljava/lang/String;Ljava/lang/String;I)V"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ val cairoSplashAnimationPatch = bytecodePatch(
|
|||||||
"7.16.53",
|
"7.16.53",
|
||||||
"7.25.53",
|
"7.25.53",
|
||||||
"8.05.51",
|
"8.05.51",
|
||||||
|
"8.10.51",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -3,9 +3,13 @@ package app.revanced.patches.music.navigation.components
|
|||||||
import app.revanced.patches.music.utils.resourceid.colorGrey
|
import app.revanced.patches.music.utils.resourceid.colorGrey
|
||||||
import app.revanced.patches.music.utils.resourceid.text1
|
import app.revanced.patches.music.utils.resourceid.text1
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
import app.revanced.util.or
|
import app.revanced.util.or
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
internal val tabLayoutFingerprint = legacyFingerprint(
|
internal val tabLayoutFingerprint = legacyFingerprint(
|
||||||
name = "tabLayoutFingerprint",
|
name = "tabLayoutFingerprint",
|
||||||
@ -30,5 +34,22 @@ internal val tabLayoutTextFingerprint = legacyFingerprint(
|
|||||||
Opcode.INVOKE_INTERFACE,
|
Opcode.INVOKE_INTERFACE,
|
||||||
Opcode.MOVE_RESULT
|
Opcode.MOVE_RESULT
|
||||||
),
|
),
|
||||||
literals = listOf(text1)
|
strings = listOf("FEmusic_search"),
|
||||||
|
literals = listOf(text1),
|
||||||
|
customFingerprint = { method, _ ->
|
||||||
|
indexOfGetVisibilityInstruction(method) >= 0 &&
|
||||||
|
indexOfSetTextInstruction(method) >= 0
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal fun indexOfGetVisibilityInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.name == "getVisibility"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun indexOfSetTextInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
|
getReference<MethodReference>()?.name == "setText"
|
||||||
|
}
|
||||||
|
@ -6,26 +6,38 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
|||||||
import app.revanced.patcher.patch.PatchException
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patches.music.general.startpage.changeStartPagePatch
|
||||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.music.utils.extension.Constants.NAVIGATION_CLASS_DESCRIPTOR
|
import app.revanced.patches.music.utils.extension.Constants.NAVIGATION_CLASS_DESCRIPTOR
|
||||||
import app.revanced.patches.music.utils.patch.PatchList.NAVIGATION_BAR_COMPONENTS
|
import app.revanced.patches.music.utils.patch.PatchList.NAVIGATION_BAR_COMPONENTS
|
||||||
|
import app.revanced.patches.music.utils.playservice.is_6_27_or_greater
|
||||||
|
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.music.utils.resourceid.colorGrey
|
import app.revanced.patches.music.utils.resourceid.colorGrey
|
||||||
import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch
|
import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch
|
||||||
import app.revanced.patches.music.utils.resourceid.text1
|
import app.revanced.patches.music.utils.resourceid.text1
|
||||||
|
import app.revanced.patches.music.utils.resourceid.ytFillSamples
|
||||||
|
import app.revanced.patches.music.utils.resourceid.ytFillYouTubeMusic
|
||||||
|
import app.revanced.patches.music.utils.resourceid.ytOutlineSamples
|
||||||
|
import app.revanced.patches.music.utils.resourceid.ytOutlineYouTubeMusic
|
||||||
import app.revanced.patches.music.utils.settings.CategoryType
|
import app.revanced.patches.music.utils.settings.CategoryType
|
||||||
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
|
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
|
||||||
import app.revanced.patches.music.utils.settings.addPreferenceWithIntent
|
import app.revanced.patches.music.utils.settings.addPreferenceWithIntent
|
||||||
import app.revanced.patches.music.utils.settings.addSwitchPreference
|
import app.revanced.patches.music.utils.settings.addSwitchPreference
|
||||||
import app.revanced.patches.music.utils.settings.settingsPatch
|
import app.revanced.patches.music.utils.settings.settingsPatch
|
||||||
|
import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
|
||||||
import app.revanced.util.fingerprint.matchOrThrow
|
import app.revanced.util.fingerprint.matchOrThrow
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
|
import app.revanced.util.replaceLiteralInstructionCall
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
private const val FLAG = "android:layout_weight"
|
private const val FLAG = "android:layout_weight"
|
||||||
@ -56,9 +68,11 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||||||
compatibleWith(COMPATIBLE_PACKAGE)
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
dependsOn(
|
dependsOn(
|
||||||
|
changeStartPagePatch,
|
||||||
navigationBarComponentsResourcePatch,
|
navigationBarComponentsResourcePatch,
|
||||||
sharedResourceIdPatch,
|
sharedResourceIdPatch,
|
||||||
settingsPatch,
|
settingsPatch,
|
||||||
|
versionCheckPatch,
|
||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
@ -105,29 +119,73 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||||||
*/
|
*/
|
||||||
tabLayoutTextFingerprint.matchOrThrow().let {
|
tabLayoutTextFingerprint.matchOrThrow().let {
|
||||||
it.method.apply {
|
it.method.apply {
|
||||||
|
val stringIndex = it.stringMatches!!.first().index
|
||||||
|
val browseIdIndex = indexOfFirstInstructionReversedOrThrow(stringIndex) {
|
||||||
|
opcode == Opcode.IGET_OBJECT &&
|
||||||
|
getReference<FieldReference>()?.type == "Ljava/lang/String;"
|
||||||
|
}
|
||||||
|
val browseIdReference = getInstruction<ReferenceInstruction>(browseIdIndex).reference as FieldReference
|
||||||
|
val fieldName = browseIdReference.name
|
||||||
|
val componentIndex = indexOfFirstInstructionOrThrow(stringIndex) {
|
||||||
|
opcode == Opcode.IGET_OBJECT &&
|
||||||
|
getReference<FieldReference>()?.toString() == browseIdReference.toString()
|
||||||
|
}
|
||||||
|
val browseIdRegister = getInstruction<TwoRegisterInstruction>(componentIndex).registerA
|
||||||
|
val componentRegister = getInstruction<TwoRegisterInstruction>(componentIndex).registerB
|
||||||
|
|
||||||
val enumIndex = it.patternMatch!!.startIndex + 3
|
val enumIndex = it.patternMatch!!.startIndex + 3
|
||||||
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
|
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
|
||||||
val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2
|
val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2
|
||||||
|
|
||||||
val pivotTabIndex = indexOfFirstInstructionOrThrow {
|
val pivotTabIndex = indexOfGetVisibilityInstruction(this)
|
||||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
|
||||||
getReference<MethodReference>()?.name == "getVisibility"
|
|
||||||
}
|
|
||||||
val pivotTabRegister =
|
val pivotTabRegister =
|
||||||
getInstruction<FiveRegisterInstruction>(pivotTabIndex).registerC
|
getInstruction<FiveRegisterInstruction>(pivotTabIndex).registerC
|
||||||
|
|
||||||
|
val spannedIndex = indexOfSetTextInstruction(this)
|
||||||
|
val spannedRegister =
|
||||||
|
getInstruction<FiveRegisterInstruction>(spannedIndex).registerD
|
||||||
|
|
||||||
addInstruction(
|
addInstruction(
|
||||||
pivotTabIndex,
|
pivotTabIndex,
|
||||||
"invoke-static {v$pivotTabRegister}, $NAVIGATION_CLASS_DESCRIPTOR->hideNavigationButton(Landroid/view/View;)V"
|
"invoke-static {v$pivotTabRegister}, $NAVIGATION_CLASS_DESCRIPTOR->hideNavigationButton(Landroid/view/View;)V"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
componentIndex + 1, """
|
||||||
|
const-string v$enumRegister, "$fieldName"
|
||||||
|
invoke-static {v$componentRegister, v$browseIdRegister, v$enumRegister}, $NAVIGATION_CLASS_DESCRIPTOR->replaceBrowseId(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
|
||||||
|
move-result-object v$browseIdRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
addInstructions(
|
||||||
|
spannedIndex, """
|
||||||
|
invoke-static {v$spannedRegister}, $NAVIGATION_CLASS_DESCRIPTOR->replaceNavigationLabel(Landroid/text/Spanned;)Landroid/text/Spanned;
|
||||||
|
move-result-object v$spannedRegister
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
addInstruction(
|
addInstruction(
|
||||||
insertEnumIndex,
|
insertEnumIndex,
|
||||||
"sput-object v$enumRegister, $NAVIGATION_CLASS_DESCRIPTOR->lastPivotTab:Ljava/lang/Enum;"
|
"invoke-static {v$enumRegister}, $NAVIGATION_CLASS_DESCRIPTOR->setLastAppNavigationEnum(Ljava/lang/Enum;)V"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val smaliInstruction = """
|
||||||
|
invoke-static {v$REGISTER_TEMPLATE_REPLACEMENT}, $NAVIGATION_CLASS_DESCRIPTOR->replaceNavigationIcon(I)I
|
||||||
|
move-result v$REGISTER_TEMPLATE_REPLACEMENT
|
||||||
|
"""
|
||||||
|
|
||||||
|
arrayOf(
|
||||||
|
ytFillSamples,
|
||||||
|
ytFillYouTubeMusic,
|
||||||
|
ytOutlineSamples,
|
||||||
|
ytOutlineYouTubeMusic,
|
||||||
|
).forEach { literal ->
|
||||||
|
replaceLiteralInstructionCall(literal, smaliInstruction)
|
||||||
|
}
|
||||||
|
|
||||||
addSwitchPreference(
|
addSwitchPreference(
|
||||||
CategoryType.NAVIGATION,
|
CategoryType.NAVIGATION,
|
||||||
"revanced_enable_custom_navigation_bar_color",
|
"revanced_enable_custom_navigation_bar_color",
|
||||||
@ -173,6 +231,22 @@ val navigationBarComponentsPatch = bytecodePatch(
|
|||||||
"revanced_hide_navigation_label",
|
"revanced_hide_navigation_label",
|
||||||
"false"
|
"false"
|
||||||
)
|
)
|
||||||
|
if (is_6_27_or_greater) {
|
||||||
|
addSwitchPreference(
|
||||||
|
CategoryType.NAVIGATION,
|
||||||
|
"revanced_replace_navigation_samples_button",
|
||||||
|
"false"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
addSwitchPreference(
|
||||||
|
CategoryType.NAVIGATION,
|
||||||
|
"revanced_replace_navigation_upgrade_button",
|
||||||
|
"false"
|
||||||
|
)
|
||||||
|
addPreferenceWithIntent(
|
||||||
|
CategoryType.NAVIGATION,
|
||||||
|
"revanced_replace_navigation_button_about"
|
||||||
|
)
|
||||||
|
|
||||||
updatePatchStatus(NAVIGATION_BAR_COMPONENTS)
|
updatePatchStatus(NAVIGATION_BAR_COMPONENTS)
|
||||||
|
|
||||||
|
@ -20,8 +20,8 @@ import app.revanced.util.or
|
|||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||||
|
|
||||||
const val AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY =
|
const val AUDIO_VIDEO_SWITCH_TOGGLE_VISIBILITY =
|
||||||
"/AudioVideoSwitcherToggleView;->setVisibility(I)V"
|
"/AudioVideoSwitcherToggleView;->setVisibility(I)V"
|
||||||
@ -44,7 +44,6 @@ internal val audioVideoSwitchToggleFingerprint = legacyFingerprint(
|
|||||||
internal val engagementPanelHeightFingerprint = legacyFingerprint(
|
internal val engagementPanelHeightFingerprint = legacyFingerprint(
|
||||||
name = "engagementPanelHeightFingerprint",
|
name = "engagementPanelHeightFingerprint",
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
// In YouTube Music 7.21.50+, there are two methods with similar structure, so this Opcode pattern must be used.
|
// In YouTube Music 7.21.50+, there are two methods with similar structure, so this Opcode pattern must be used.
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
@ -54,6 +53,7 @@ internal val engagementPanelHeightFingerprint = legacyFingerprint(
|
|||||||
),
|
),
|
||||||
parameters = emptyList(),
|
parameters = emptyList(),
|
||||||
customFingerprint = { method, _ ->
|
customFingerprint = { method, _ ->
|
||||||
|
AccessFlags.FINAL.isSet(method.accessFlags) &&
|
||||||
method.containsLiteralInstruction(1) &&
|
method.containsLiteralInstruction(1) &&
|
||||||
method.indexOfFirstInstruction {
|
method.indexOfFirstInstruction {
|
||||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||||
@ -65,7 +65,6 @@ internal val engagementPanelHeightFingerprint = legacyFingerprint(
|
|||||||
internal val engagementPanelHeightParentFingerprint = legacyFingerprint(
|
internal val engagementPanelHeightParentFingerprint = legacyFingerprint(
|
||||||
name = "engagementPanelHeightParentFingerprint",
|
name = "engagementPanelHeightParentFingerprint",
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
|
||||||
opcodes = listOf(Opcode.NEW_ARRAY),
|
opcodes = listOf(Opcode.NEW_ARRAY),
|
||||||
parameters = emptyList(),
|
parameters = emptyList(),
|
||||||
customFingerprint = custom@{ method, _ ->
|
customFingerprint = custom@{ method, _ ->
|
||||||
@ -75,9 +74,12 @@ internal val engagementPanelHeightParentFingerprint = legacyFingerprint(
|
|||||||
if (method.returnType == "Ljava/lang/Object;") {
|
if (method.returnType == "Ljava/lang/Object;") {
|
||||||
return@custom false
|
return@custom false
|
||||||
}
|
}
|
||||||
|
if (!AccessFlags.FINAL.isSet(method.accessFlags)) {
|
||||||
|
return@custom false
|
||||||
|
}
|
||||||
method.indexOfFirstInstruction {
|
method.indexOfFirstInstruction {
|
||||||
opcode == Opcode.CHECK_CAST &&
|
opcode == Opcode.CHECK_CAST &&
|
||||||
(this as? ReferenceInstruction)?.reference?.toString() == "Lcom/google/android/libraries/youtube/engagementpanel/size/EngagementPanelSizeBehavior;"
|
getReference<TypeReference>()?.type == "Lcom/google/android/libraries/youtube/engagementpanel/size/EngagementPanelSizeBehavior;"
|
||||||
} >= 0
|
} >= 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,8 @@ internal object Constants {
|
|||||||
"6.51.53", // This is the latest version of YouTube Music 6.xx.xx
|
"6.51.53", // This is the latest version of YouTube Music 6.xx.xx
|
||||||
"7.16.53", // This is the latest version that supports the 'Spoof app version' patch.
|
"7.16.53", // This is the latest version that supports the 'Spoof app version' patch.
|
||||||
"7.25.53", // This is the last supported version for 2024.
|
"7.25.53", // This is the last supported version for 2024.
|
||||||
"8.05.51", // This is the latest version supported by the RVX patch.
|
"8.05.51", // This was the latest version supported by the previous RVX patch.
|
||||||
|
"8.10.51", // This is the latest version supported by the RVX patch.
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
@ -64,7 +64,8 @@ private const val CLIENT_INFO_CLASS_DESCRIPTOR =
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val spoofClientPatch = bytecodePatch(
|
val spoofClientPatch = bytecodePatch(
|
||||||
SPOOF_CLIENT.title,
|
SPOOF_CLIENT.title,
|
||||||
SPOOF_CLIENT.summary
|
SPOOF_CLIENT.summary,
|
||||||
|
false,
|
||||||
) {
|
) {
|
||||||
compatibleWith(COMPATIBLE_PACKAGE)
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
@ -359,7 +360,7 @@ val spoofClientPatch = bytecodePatch(
|
|||||||
addSwitchPreference(
|
addSwitchPreference(
|
||||||
CategoryType.MISC,
|
CategoryType.MISC,
|
||||||
"revanced_spoof_client",
|
"revanced_spoof_client",
|
||||||
"true"
|
"false"
|
||||||
)
|
)
|
||||||
addPreferenceWithIntent(
|
addPreferenceWithIntent(
|
||||||
CategoryType.MISC,
|
CategoryType.MISC,
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
package app.revanced.patches.music.utils.fix.parameter
|
||||||
|
|
||||||
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
|
import app.revanced.util.or
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
|
|
||||||
|
internal val subtitleWindowFingerprint = legacyFingerprint(
|
||||||
|
name = "subtitleWindowFingerprint",
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
parameters = listOf("I", "I", "I", "Z", "Z"),
|
||||||
|
strings = listOf("invalid anchorHorizontalPos: %s"),
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If this flag is activated, a playback issue occurs in age-restricted videos.
|
||||||
|
*/
|
||||||
|
internal const val AGE_RESTRICTED_PLAYBACK_FEATURE_FLAG = 45651506L
|
||||||
|
|
||||||
|
internal val ageRestrictedPlaybackFeatureFlagFingerprint = legacyFingerprint(
|
||||||
|
name = "ageRestrictedPlaybackFeatureFlagFingerprint",
|
||||||
|
returnType = "Z",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = emptyList(),
|
||||||
|
literals = listOf(AGE_RESTRICTED_PLAYBACK_FEATURE_FLAG),
|
||||||
|
)
|
@ -0,0 +1,82 @@
|
|||||||
|
package app.revanced.patches.music.utils.fix.parameter
|
||||||
|
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
|
import app.revanced.patches.music.utils.extension.Constants.MISC_PATH
|
||||||
|
import app.revanced.patches.music.utils.patch.PatchList.SPOOF_PLAYER_PARAMETER
|
||||||
|
import app.revanced.patches.music.utils.settings.CategoryType
|
||||||
|
import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus
|
||||||
|
import app.revanced.patches.music.utils.settings.addSwitchPreference
|
||||||
|
import app.revanced.patches.music.utils.settings.settingsPatch
|
||||||
|
import app.revanced.patches.music.video.information.videoInformationPatch
|
||||||
|
import app.revanced.patches.music.video.playerresponse.Hook
|
||||||
|
import app.revanced.patches.music.video.playerresponse.addPlayerResponseMethodHook
|
||||||
|
import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch
|
||||||
|
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
||||||
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
|
import app.revanced.util.fingerprint.resolvable
|
||||||
|
|
||||||
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
|
"$MISC_PATH/SpoofPlayerParameterPatch;"
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
val spoofPlayerParameterPatch = bytecodePatch(
|
||||||
|
SPOOF_PLAYER_PARAMETER.title,
|
||||||
|
SPOOF_PLAYER_PARAMETER.summary
|
||||||
|
) {
|
||||||
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
|
dependsOn(
|
||||||
|
settingsPatch,
|
||||||
|
videoInformationPatch,
|
||||||
|
playerResponseMethodHookPatch,
|
||||||
|
)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
|
||||||
|
addPlayerResponseMethodHook(
|
||||||
|
Hook.PlayerParameter(
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->spoofParameter(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
// region fix for subtitles position
|
||||||
|
|
||||||
|
subtitleWindowFingerprint.methodOrThrow().addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
invoke-static {p1, p2, p3, p4, p5}, $EXTENSION_CLASS_DESCRIPTOR->fixSubtitleWindowPosition(IIIZZ)[I
|
||||||
|
move-result-object v0
|
||||||
|
const/4 v1, 0x0
|
||||||
|
aget p1, v0, v1 # ap, anchor position
|
||||||
|
const/4 v1, 0x1
|
||||||
|
aget p2, v0, v1 # ah, horizontal anchor
|
||||||
|
const/4 v1, 0x2
|
||||||
|
aget p3, v0, v1 # av, vertical anchor
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region fix for feature flags
|
||||||
|
|
||||||
|
if (ageRestrictedPlaybackFeatureFlagFingerprint.resolvable()) {
|
||||||
|
ageRestrictedPlaybackFeatureFlagFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
AGE_RESTRICTED_PLAYBACK_FEATURE_FLAG,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->forceDisableAgeRestrictedPlaybackFeatureFlag(Z)Z"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
addSwitchPreference(
|
||||||
|
CategoryType.MISC,
|
||||||
|
"revanced_spoof_player_parameter",
|
||||||
|
"true"
|
||||||
|
)
|
||||||
|
|
||||||
|
updatePatchStatus(SPOOF_PLAYER_PARAMETER)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -157,6 +157,10 @@ internal enum class PatchList(
|
|||||||
"Spoof client",
|
"Spoof client",
|
||||||
"Adds options to spoof the client to allow playback."
|
"Adds options to spoof the client to allow playback."
|
||||||
),
|
),
|
||||||
|
SPOOF_PLAYER_PARAMETER(
|
||||||
|
"Spoof player parameter",
|
||||||
|
"Adds options to spoof player parameter to allow playback."
|
||||||
|
),
|
||||||
TRANSLATIONS_FOR_YOUTUBE_MUSIC(
|
TRANSLATIONS_FOR_YOUTUBE_MUSIC(
|
||||||
"Translations for YouTube Music",
|
"Translations for YouTube Music",
|
||||||
"Add translations or remove string resources."
|
"Add translations or remove string resources."
|
||||||
|
@ -105,6 +105,14 @@ var trimSilenceSwitch = -1L
|
|||||||
private set
|
private set
|
||||||
var varispeedUnavailableTitle = -1L
|
var varispeedUnavailableTitle = -1L
|
||||||
private set
|
private set
|
||||||
|
var ytFillSamples = -1L
|
||||||
|
private set
|
||||||
|
var ytFillYouTubeMusic = -1L
|
||||||
|
private set
|
||||||
|
var ytOutlineSamples = -1L
|
||||||
|
private set
|
||||||
|
var ytOutlineYouTubeMusic = -1L
|
||||||
|
private set
|
||||||
var ytmLogo = -1L
|
var ytmLogo = -1L
|
||||||
private set
|
private set
|
||||||
var ytmLogoRingo2 = -1L
|
var ytmLogoRingo2 = -1L
|
||||||
@ -300,6 +308,22 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||||||
STRING,
|
STRING,
|
||||||
"varispeed_unavailable_title"
|
"varispeed_unavailable_title"
|
||||||
]
|
]
|
||||||
|
ytFillSamples = resourceMappings[
|
||||||
|
DRAWABLE,
|
||||||
|
"yt_fill_samples_vd_theme_24",
|
||||||
|
]
|
||||||
|
ytFillYouTubeMusic = resourceMappings[
|
||||||
|
DRAWABLE,
|
||||||
|
"yt_fill_youtube_music_vd_theme_24",
|
||||||
|
]
|
||||||
|
ytOutlineSamples = resourceMappings[
|
||||||
|
DRAWABLE,
|
||||||
|
"yt_outline_samples_vd_theme_24",
|
||||||
|
]
|
||||||
|
ytOutlineYouTubeMusic = resourceMappings[
|
||||||
|
DRAWABLE,
|
||||||
|
"yt_outline_youtube_music_vd_theme_24",
|
||||||
|
]
|
||||||
ytmLogo = resourceMappings[
|
ytmLogo = resourceMappings[
|
||||||
DRAWABLE,
|
DRAWABLE,
|
||||||
"ytm_logo",
|
"ytm_logo",
|
||||||
|
@ -13,6 +13,9 @@ import app.revanced.patches.music.utils.extension.Constants.SHARED_PATH
|
|||||||
import app.revanced.patches.music.utils.playbackSpeedFingerprint
|
import app.revanced.patches.music.utils.playbackSpeedFingerprint
|
||||||
import app.revanced.patches.music.utils.playbackSpeedParentFingerprint
|
import app.revanced.patches.music.utils.playbackSpeedParentFingerprint
|
||||||
import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch
|
import app.revanced.patches.music.utils.resourceid.sharedResourceIdPatch
|
||||||
|
import app.revanced.patches.music.video.playerresponse.Hook
|
||||||
|
import app.revanced.patches.music.video.playerresponse.addPlayerResponseMethodHook
|
||||||
|
import app.revanced.patches.music.video.playerresponse.playerResponseMethodHookPatch
|
||||||
import app.revanced.patches.shared.mdxPlayerDirectorSetVideoStageFingerprint
|
import app.revanced.patches.shared.mdxPlayerDirectorSetVideoStageFingerprint
|
||||||
import app.revanced.patches.shared.videoLengthFingerprint
|
import app.revanced.patches.shared.videoLengthFingerprint
|
||||||
import app.revanced.util.addStaticFieldToExtension
|
import app.revanced.util.addStaticFieldToExtension
|
||||||
@ -71,7 +74,10 @@ private var videoTimeConstructorInsertIndex = 2
|
|||||||
val videoInformationPatch = bytecodePatch(
|
val videoInformationPatch = bytecodePatch(
|
||||||
description = "videoInformationPatch",
|
description = "videoInformationPatch",
|
||||||
) {
|
) {
|
||||||
dependsOn(sharedResourceIdPatch)
|
dependsOn(
|
||||||
|
playerResponseMethodHookPatch,
|
||||||
|
sharedResourceIdPatch
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
fun addSeekInterfaceMethods(
|
fun addSeekInterfaceMethods(
|
||||||
@ -241,7 +247,18 @@ val videoInformationPatch = bytecodePatch(
|
|||||||
* Set current video id
|
* Set current video id
|
||||||
*/
|
*/
|
||||||
videoIdHook("$EXTENSION_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
videoIdHook("$EXTENSION_CLASS_DESCRIPTOR->setVideoId(Ljava/lang/String;)V")
|
||||||
|
addPlayerResponseMethodHook(
|
||||||
|
Hook.VideoId(
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->setPlayerResponseVideoId(Ljava/lang/String;)V"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// Call before any other video id hooks,
|
||||||
|
// so they can use VideoInformation and check if the video id is for a Short.
|
||||||
|
addPlayerResponseMethodHook(
|
||||||
|
Hook.PlayerParameterBeforeVideoId(
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->newPlayerResponseParameter(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"
|
||||||
|
)
|
||||||
|
)
|
||||||
/**
|
/**
|
||||||
* Hook current playback speed
|
* Hook current playback speed
|
||||||
*/
|
*/
|
||||||
|
@ -11,8 +11,7 @@ private val PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST = listOf(
|
|||||||
"[B",
|
"[B",
|
||||||
"Ljava/lang/String;", // Player parameters proto buffer.
|
"Ljava/lang/String;", // Player parameters proto buffer.
|
||||||
"Ljava/lang/String;", // PlaylistId.
|
"Ljava/lang/String;", // PlaylistId.
|
||||||
"I", // PlaylistIndex.
|
"I" // PlaylistIndex.
|
||||||
"I"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +29,7 @@ internal val playerParameterBuilderFingerprint = legacyFingerprint(
|
|||||||
return@custom false
|
return@custom false
|
||||||
}
|
}
|
||||||
|
|
||||||
val startsWithMethodParameterList = parameterTypes.slice(0..5)
|
val startsWithMethodParameterList = parameterTypes.slice(0..4)
|
||||||
|
|
||||||
parametersEqual(
|
parametersEqual(
|
||||||
PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST,
|
PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST,
|
||||||
|
@ -1,22 +1,35 @@
|
|||||||
package app.revanced.patches.music.video.playerresponse
|
package app.revanced.patches.music.video.playerresponse
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||||
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
|
import app.revanced.patches.music.utils.extension.sharedExtensionPatch
|
||||||
import app.revanced.patches.music.utils.playservice.is_7_03_or_greater
|
import app.revanced.patches.music.utils.playservice.is_7_03_or_greater
|
||||||
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
import app.revanced.patches.music.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
|
|
||||||
|
private val hooks = mutableSetOf<Hook>()
|
||||||
|
|
||||||
|
fun addPlayerResponseMethodHook(hook: Hook) {
|
||||||
|
hooks += hook
|
||||||
|
}
|
||||||
|
|
||||||
private const val REGISTER_VIDEO_ID = "p1"
|
private const val REGISTER_VIDEO_ID = "p1"
|
||||||
|
private const val REGISTER_PLAYER_PARAMETER = "p3"
|
||||||
private const val REGISTER_PLAYLIST_ID = "p4"
|
private const val REGISTER_PLAYLIST_ID = "p4"
|
||||||
private const val REGISTER_PLAYLIST_INDEX = "p5"
|
private const val REGISTER_PLAYLIST_INDEX = "p5"
|
||||||
|
|
||||||
private lateinit var playerResponseMethod: MutableMethod
|
private lateinit var playerResponseMethod: MutableMethod
|
||||||
|
private var numberOfInstructionsAdded = 0
|
||||||
|
|
||||||
val playerResponseMethodHookPatch = bytecodePatch(
|
val playerResponseMethodHookPatch = bytecodePatch(
|
||||||
description = "playerResponseMethodHookPatch"
|
description = "playerResponseMethodHookPatch"
|
||||||
) {
|
) {
|
||||||
dependsOn(versionCheckPatch)
|
dependsOn(
|
||||||
|
sharedExtensionPatch,
|
||||||
|
versionCheckPatch,
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
playerResponseMethod = if (is_7_03_or_greater) {
|
playerResponseMethod = if (is_7_03_or_greater) {
|
||||||
@ -25,16 +38,70 @@ val playerResponseMethodHookPatch = bytecodePatch(
|
|||||||
playerParameterBuilderLegacyFingerprint
|
playerParameterBuilderLegacyFingerprint
|
||||||
}.methodOrThrow()
|
}.methodOrThrow()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
finalize {
|
||||||
|
fun hookVideoId(hook: Hook) {
|
||||||
|
playerResponseMethod.addInstruction(
|
||||||
|
0,
|
||||||
|
"invoke-static {$REGISTER_VIDEO_ID}, $hook",
|
||||||
|
)
|
||||||
|
numberOfInstructionsAdded++
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hookVideoIdAndPlaylistId(hook: Hook) {
|
||||||
|
playerResponseMethod.addInstruction(
|
||||||
|
0,
|
||||||
|
"invoke-static {$REGISTER_VIDEO_ID, $REGISTER_PLAYLIST_ID, $REGISTER_PLAYLIST_INDEX}, $hook",
|
||||||
|
)
|
||||||
|
numberOfInstructionsAdded++
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hookPlayerParameter(hook: Hook) {
|
||||||
|
playerResponseMethod.addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
invoke-static {$REGISTER_VIDEO_ID, v0}, $hook
|
||||||
|
move-result-object v0
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
numberOfInstructionsAdded += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the order in order to preserve insertion order of the hooks.
|
||||||
|
val beforeVideoIdHooks =
|
||||||
|
hooks.filterIsInstance<Hook.PlayerParameterBeforeVideoId>().asReversed()
|
||||||
|
val videoIdHooks = hooks.filterIsInstance<Hook.VideoId>().asReversed()
|
||||||
|
val videoIdAndPlaylistIdHooks = hooks.filterIsInstance<Hook.VideoIdAndPlaylistId>().asReversed()
|
||||||
|
val afterVideoIdHooks = hooks.filterIsInstance<Hook.PlayerParameter>().asReversed()
|
||||||
|
|
||||||
|
// Add the hooks in this specific order as they insert instructions at the beginning of the method.
|
||||||
|
afterVideoIdHooks.forEach(::hookPlayerParameter)
|
||||||
|
videoIdAndPlaylistIdHooks.forEach(::hookVideoIdAndPlaylistId)
|
||||||
|
videoIdHooks.forEach(::hookVideoId)
|
||||||
|
beforeVideoIdHooks.forEach(::hookPlayerParameter)
|
||||||
|
|
||||||
|
playerResponseMethod.apply {
|
||||||
|
addInstruction(
|
||||||
|
0,
|
||||||
|
"move-object/from16 v0, $REGISTER_PLAYER_PARAMETER"
|
||||||
|
)
|
||||||
|
numberOfInstructionsAdded++
|
||||||
|
|
||||||
|
// Move the modified register back.
|
||||||
|
addInstruction(
|
||||||
|
numberOfInstructionsAdded,
|
||||||
|
"move-object/from16 $REGISTER_PLAYER_PARAMETER, v0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hookPlayerResponse(
|
sealed class Hook(private val methodDescriptor: String) {
|
||||||
descriptor: String,
|
class VideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||||
onlyVideoId: Boolean = false
|
class VideoIdAndPlaylistId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||||
) {
|
|
||||||
val smaliInstruction = if (onlyVideoId)
|
|
||||||
"invoke-static {$REGISTER_VIDEO_ID}, $descriptor"
|
|
||||||
else
|
|
||||||
"invoke-static {$REGISTER_VIDEO_ID, $REGISTER_PLAYLIST_ID, $REGISTER_PLAYLIST_INDEX}, $descriptor"
|
|
||||||
|
|
||||||
playerResponseMethod.addInstruction(0, smaliInstruction)
|
class PlayerParameter(methodDescriptor: String) : Hook(methodDescriptor)
|
||||||
|
class PlayerParameterBeforeVideoId(methodDescriptor: String) : Hook(methodDescriptor)
|
||||||
|
|
||||||
|
override fun toString() = methodDescriptor
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,11 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH
|
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH
|
||||||
import app.revanced.patches.reddit.utils.patch.PatchList.HIDE_ADS
|
import app.revanced.patches.reddit.utils.patch.PatchList.HIDE_ADS
|
||||||
|
import app.revanced.patches.reddit.utils.settings.is_2025_06_or_greater
|
||||||
import app.revanced.patches.reddit.utils.settings.settingsPatch
|
import app.revanced.patches.reddit.utils.settings.settingsPatch
|
||||||
import app.revanced.patches.reddit.utils.settings.updatePatchStatus
|
import app.revanced.patches.reddit.utils.settings.updatePatchStatus
|
||||||
import app.revanced.util.findMutableMethodOf
|
import app.revanced.util.findMutableMethodOf
|
||||||
@ -78,13 +80,8 @@ val adsPatch = bytecodePatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// region Filter comment ads
|
// region Filter comment ads
|
||||||
classes.forEach { classDef ->
|
fun MutableMethod.hook() =
|
||||||
classDef.methods.forEach { method ->
|
addInstructionsWithLabels(
|
||||||
if (method.isCommentAdsMethod()) {
|
|
||||||
proxy(classDef)
|
|
||||||
.mutableClass
|
|
||||||
.findMutableMethodOf(method)
|
|
||||||
.addInstructionsWithLabels(
|
|
||||||
0, """
|
0, """
|
||||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->hideCommentAds()Z
|
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->hideCommentAds()Z
|
||||||
move-result v0
|
move-result v0
|
||||||
@ -94,6 +91,22 @@ val adsPatch = bytecodePatch(
|
|||||||
nop
|
nop
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
if (is_2025_06_or_greater) {
|
||||||
|
listOf(
|
||||||
|
commentAdCommentScreenAdViewFingerprint,
|
||||||
|
commentAdDetailListHeaderViewFingerprint
|
||||||
|
).forEach { fingerprint ->
|
||||||
|
fingerprint.methodOrThrow().hook()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
classes.forEach { classDef ->
|
||||||
|
classDef.methods.forEach { method ->
|
||||||
|
if (method.isCommentAdsMethod()) {
|
||||||
|
proxy(classDef)
|
||||||
|
.mutableClass
|
||||||
|
.findMutableMethodOf(method)
|
||||||
|
.hook()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,28 @@ internal val adPostFingerprint = legacyFingerprint(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal val commentAdCommentScreenAdViewFingerprint = legacyFingerprint(
|
||||||
|
name = "commentAdCommentScreenAdViewFingerprint",
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
strings = listOf("ad"),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.type.endsWith("/CommentScreenAdView;")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val commentAdDetailListHeaderViewFingerprint = legacyFingerprint(
|
||||||
|
name = "commentAdDetailListHeaderViewFingerprint",
|
||||||
|
returnType = "V",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
strings = listOf("ad"),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.type.endsWith("/DetailListHeaderView;")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
internal val newAdPostFingerprint = legacyFingerprint(
|
internal val newAdPostFingerprint = legacyFingerprint(
|
||||||
name = "newAdPostFingerprint",
|
name = "newAdPostFingerprint",
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package app.revanced.patches.reddit.layout.navigation
|
package app.revanced.patches.reddit.layout.navigation
|
||||||
|
|
||||||
|
import app.revanced.util.containsLiteralInstruction
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstruction
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
@ -8,6 +9,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||||
|
|
||||||
internal val bottomNavScreenFingerprint = legacyFingerprint(
|
internal val bottomNavScreenFingerprint = legacyFingerprint(
|
||||||
name = "bottomNavScreenFingerprint",
|
name = "bottomNavScreenFingerprint",
|
||||||
@ -62,13 +64,32 @@ internal val bottomNavScreenOnGlobalLayoutFingerprint = legacyFingerprint(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private const val CHAT_BUTTON_MAGIC_NUMBER = 1906671695L
|
||||||
|
|
||||||
internal val bottomNavScreenSetupBottomNavigationFingerprint = legacyFingerprint(
|
internal val bottomNavScreenSetupBottomNavigationFingerprint = legacyFingerprint(
|
||||||
name = "bottomNavScreenSetupBottomNavigationFingerprint",
|
name = "bottomNavScreenSetupBottomNavigationFingerprint",
|
||||||
returnType = "V",
|
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
opcodes = listOf(Opcode.FILLED_NEW_ARRAY),
|
opcodes = listOf(Opcode.FILLED_NEW_ARRAY),
|
||||||
customFingerprint = { method, classDef ->
|
customFingerprint = { method, classDef ->
|
||||||
classDef.type.startsWith("Lcom/reddit/launch/bottomnav/BottomNavScreen${'$'}setupBottomNavigation${'$'}") &&
|
method.containsLiteralInstruction(CHAT_BUTTON_MAGIC_NUMBER) &&
|
||||||
method.name == "invoke"
|
method.name == "invoke" &&
|
||||||
|
indexOfButtonsArrayInstruction(method) >= 0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal val composeBottomNavScreenFingerprint = legacyFingerprint(
|
||||||
|
name = "composeBottomNavScreenFingerprint",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("Landroid/content/res/Resources;"),
|
||||||
|
opcodes = listOf(Opcode.FILLED_NEW_ARRAY),
|
||||||
|
customFingerprint = { method, classDef ->
|
||||||
|
classDef.type == "Lcom/reddit/launch/bottomnav/ComposeBottomNavScreen;" &&
|
||||||
|
indexOfButtonsArrayInstruction(method) >= 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun indexOfButtonsArrayInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.FILLED_NEW_ARRAY &&
|
||||||
|
getReference<TypeReference>()?.type?.startsWith("[Lcom/reddit/widget/bottomnav/") == true
|
||||||
|
}
|
||||||
|
@ -8,12 +8,12 @@ import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACK
|
|||||||
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH
|
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH
|
||||||
import app.revanced.patches.reddit.utils.patch.PatchList.HIDE_NAVIGATION_BUTTONS
|
import app.revanced.patches.reddit.utils.patch.PatchList.HIDE_NAVIGATION_BUTTONS
|
||||||
import app.revanced.patches.reddit.utils.settings.is_2024_26_or_greater
|
import app.revanced.patches.reddit.utils.settings.is_2024_26_or_greater
|
||||||
|
import app.revanced.patches.reddit.utils.settings.is_2025_06_or_greater
|
||||||
import app.revanced.patches.reddit.utils.settings.settingsPatch
|
import app.revanced.patches.reddit.utils.settings.settingsPatch
|
||||||
import app.revanced.patches.reddit.utils.settings.updatePatchStatus
|
import app.revanced.patches.reddit.utils.settings.updatePatchStatus
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
import app.revanced.util.fingerprint.resolvable
|
import app.revanced.util.fingerprint.resolvable
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
@ -34,8 +34,13 @@ val navigationButtonsPatch = bytecodePatch(
|
|||||||
execute {
|
execute {
|
||||||
|
|
||||||
if (is_2024_26_or_greater) {
|
if (is_2024_26_or_greater) {
|
||||||
bottomNavScreenSetupBottomNavigationFingerprint.methodOrThrow().apply {
|
val fingerprints = mutableListOf(bottomNavScreenSetupBottomNavigationFingerprint)
|
||||||
val arrayIndex = indexOfFirstInstructionReversedOrThrow(Opcode.FILLED_NEW_ARRAY)
|
|
||||||
|
if (is_2025_06_or_greater) fingerprints += composeBottomNavScreenFingerprint
|
||||||
|
|
||||||
|
fingerprints.forEach { fingerprint ->
|
||||||
|
fingerprint.methodOrThrow().apply {
|
||||||
|
val arrayIndex = indexOfButtonsArrayInstruction(this)
|
||||||
val arrayRegister =
|
val arrayRegister =
|
||||||
getInstruction<OneRegisterInstruction>(arrayIndex + 1).registerA
|
getInstruction<OneRegisterInstruction>(arrayIndex + 1).registerA
|
||||||
|
|
||||||
@ -46,6 +51,7 @@ val navigationButtonsPatch = bytecodePatch(
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (bottomNavScreenFingerprint.resolvable()) {
|
if (bottomNavScreenFingerprint.resolvable()) {
|
||||||
val bottomNavScreenMutableClass = with(bottomNavScreenFingerprint.methodOrThrow()) {
|
val bottomNavScreenMutableClass = with(bottomNavScreenFingerprint.methodOrThrow()) {
|
||||||
|
@ -1,9 +1,32 @@
|
|||||||
package app.revanced.patches.reddit.layout.screenshotpopup
|
package app.revanced.patches.reddit.layout.screenshotpopup
|
||||||
|
|
||||||
|
import app.revanced.patches.reddit.utils.resourceid.screenShotShareBanner
|
||||||
|
import app.revanced.util.containsLiteralInstruction
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reddit 2025.06.0 ~
|
||||||
|
*/
|
||||||
internal val screenshotTakenBannerFingerprint = legacyFingerprint(
|
internal val screenshotTakenBannerFingerprint = legacyFingerprint(
|
||||||
name = "screenshotTakenBannerFingerprint",
|
name = "screenshotTakenBannerFingerprint",
|
||||||
|
returnType = "L",
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.CONST_4,
|
||||||
|
Opcode.IF_NE,
|
||||||
|
),
|
||||||
|
customFingerprint = { method, classDef ->
|
||||||
|
method.containsLiteralInstruction(screenShotShareBanner) &&
|
||||||
|
classDef.type.startsWith("Lcom/reddit/sharing/screenshot/composables/") &&
|
||||||
|
method.name == "invoke"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ~ Reddit 2025.05.1
|
||||||
|
*/
|
||||||
|
internal val screenshotTakenBannerLegacyFingerprint = legacyFingerprint(
|
||||||
|
name = "screenshotTakenBannerLegacyFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
parameters = listOf("Landroidx/compose/runtime/", "I"),
|
parameters = listOf("Landroidx/compose/runtime/", "I"),
|
||||||
customFingerprint = { method, classDef ->
|
customFingerprint = { method, classDef ->
|
||||||
|
@ -7,9 +7,17 @@ import app.revanced.patcher.util.smali.ExternalLabel
|
|||||||
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.reddit.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH
|
import app.revanced.patches.reddit.utils.extension.Constants.PATCHES_PATH
|
||||||
import app.revanced.patches.reddit.utils.patch.PatchList.DISABLE_SCREENSHOT_POPUP
|
import app.revanced.patches.reddit.utils.patch.PatchList.DISABLE_SCREENSHOT_POPUP
|
||||||
|
import app.revanced.patches.reddit.utils.resourceid.screenShotShareBanner
|
||||||
|
import app.revanced.patches.reddit.utils.resourceid.sharedResourceIdPatch
|
||||||
|
import app.revanced.patches.reddit.utils.settings.is_2025_06_or_greater
|
||||||
import app.revanced.patches.reddit.utils.settings.settingsPatch
|
import app.revanced.patches.reddit.utils.settings.settingsPatch
|
||||||
import app.revanced.patches.reddit.utils.settings.updatePatchStatus
|
import app.revanced.patches.reddit.utils.settings.updatePatchStatus
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||||
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
private const val EXTENSION_METHOD_DESCRIPTOR =
|
private const val EXTENSION_METHOD_DESCRIPTOR =
|
||||||
"$PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup()Z"
|
"$PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup()Z"
|
||||||
@ -21,10 +29,30 @@ val screenshotPopupPatch = bytecodePatch(
|
|||||||
) {
|
) {
|
||||||
compatibleWith(COMPATIBLE_PACKAGE)
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
dependsOn(settingsPatch)
|
dependsOn(
|
||||||
|
settingsPatch,
|
||||||
|
sharedResourceIdPatch,
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
|
||||||
|
if (is_2025_06_or_greater) {
|
||||||
screenshotTakenBannerFingerprint.methodOrThrow().apply {
|
screenshotTakenBannerFingerprint.methodOrThrow().apply {
|
||||||
|
val literalIndex = indexOfFirstLiteralInstructionOrThrow(screenShotShareBanner)
|
||||||
|
val insertIndex = indexOfFirstInstructionReversedOrThrow(literalIndex, Opcode.CONST_4)
|
||||||
|
val insertRegister = getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||||
|
val jumpIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.SGET_OBJECT)
|
||||||
|
|
||||||
|
addInstructionsWithLabels(
|
||||||
|
insertIndex, """
|
||||||
|
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
|
||||||
|
move-result v$insertRegister
|
||||||
|
if-nez v$insertRegister, :hidden
|
||||||
|
""", ExternalLabel("hidden", getInstruction(jumpIndex))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
screenshotTakenBannerLegacyFingerprint.methodOrThrow().apply {
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
0, """
|
0, """
|
||||||
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
|
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
|
||||||
@ -34,6 +62,7 @@ val screenshotPopupPatch = bytecodePatch(
|
|||||||
""", ExternalLabel("dismiss", getInstruction(0))
|
""", ExternalLabel("dismiss", getInstruction(0))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updatePatchStatus(
|
updatePatchStatus(
|
||||||
"enableScreenshotPopup",
|
"enableScreenshotPopup",
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package app.revanced.patches.reddit.utils.resourceid
|
||||||
|
|
||||||
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patches.shared.mapping.ResourceType.STRING
|
||||||
|
import app.revanced.patches.shared.mapping.get
|
||||||
|
import app.revanced.patches.shared.mapping.resourceMappingPatch
|
||||||
|
import app.revanced.patches.shared.mapping.resourceMappings
|
||||||
|
|
||||||
|
var screenShotShareBanner = -1L
|
||||||
|
private set
|
||||||
|
|
||||||
|
internal val sharedResourceIdPatch = resourcePatch(
|
||||||
|
description = "sharedResourceIdPatch"
|
||||||
|
) {
|
||||||
|
dependsOn(resourceMappingPatch)
|
||||||
|
|
||||||
|
execute {
|
||||||
|
screenShotShareBanner = resourceMappings[
|
||||||
|
STRING,
|
||||||
|
"screenshot_share_banner_title",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
@ -259,13 +259,7 @@ val feedComponentsPatch = bytecodePatch(
|
|||||||
elementParserFingerprint.matchOrThrow(elementParserParentFingerprint).let {
|
elementParserFingerprint.matchOrThrow(elementParserParentFingerprint).let {
|
||||||
it.method.apply {
|
it.method.apply {
|
||||||
val freeRegister = implementation!!.registerCount - parameters.size - 2
|
val freeRegister = implementation!!.registerCount - parameters.size - 2
|
||||||
val insertIndex = indexOfFirstInstructionOrThrow {
|
val insertIndex = indexOfBufferParserInstruction(this)
|
||||||
val reference = getReference<MethodReference>()
|
|
||||||
|
|
||||||
reference?.parameterTypes?.size == 1 &&
|
|
||||||
reference.parameterTypes.first() == "[B" &&
|
|
||||||
reference.returnType.startsWith("L")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_19_46_or_greater) {
|
if (is_19_46_or_greater) {
|
||||||
val objectIndex = indexOfFirstInstructionReversedOrThrow(insertIndex, Opcode.IGET_OBJECT)
|
val objectIndex = indexOfFirstInstructionReversedOrThrow(insertIndex, Opcode.IGET_OBJECT)
|
||||||
|
@ -11,9 +11,13 @@ import app.revanced.patches.youtube.utils.resourceid.filterBarHeight
|
|||||||
import app.revanced.patches.youtube.utils.resourceid.horizontalCardList
|
import app.revanced.patches.youtube.utils.resourceid.horizontalCardList
|
||||||
import app.revanced.patches.youtube.utils.resourceid.relatedChipCloudMargin
|
import app.revanced.patches.youtube.utils.resourceid.relatedChipCloudMargin
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
|
import app.revanced.util.getReference
|
||||||
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
import app.revanced.util.or
|
import app.revanced.util.or
|
||||||
import com.android.tools.smali.dexlib2.AccessFlags
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
|
||||||
internal val breakingNewsFingerprint = legacyFingerprint(
|
internal val breakingNewsFingerprint = legacyFingerprint(
|
||||||
name = "breakingNewsFingerprint",
|
name = "breakingNewsFingerprint",
|
||||||
@ -90,9 +94,19 @@ internal val elementParserFingerprint = legacyFingerprint(
|
|||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.RETURN_OBJECT
|
Opcode.RETURN_OBJECT
|
||||||
)
|
),
|
||||||
|
customFingerprint = { method, _ ->
|
||||||
|
indexOfBufferParserInstruction(method) >= 0
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal fun indexOfBufferParserInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
val reference = getReference<MethodReference>()
|
||||||
|
reference?.parameterTypes?.firstOrNull() == "[B" &&
|
||||||
|
reference.returnType.startsWith("L")
|
||||||
|
}
|
||||||
|
|
||||||
internal val elementParserParentFingerprint = legacyFingerprint(
|
internal val elementParserParentFingerprint = legacyFingerprint(
|
||||||
name = "elementParserParentFingerprint",
|
name = "elementParserParentFingerprint",
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.general.layoutswitch
|
package app.revanced.patches.youtube.general.formfactor
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
@ -6,30 +6,37 @@ import app.revanced.patcher.patch.bytecodePatch
|
|||||||
import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint
|
import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint
|
||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.CHANGE_LAYOUT
|
import app.revanced.patches.youtube.utils.navigation.hookNavigationButtonCreated
|
||||||
|
import app.revanced.patches.youtube.utils.navigation.navigationBarHookPatch
|
||||||
|
import app.revanced.patches.youtube.utils.patch.PatchList.CHANGE_FORM_FACTOR
|
||||||
|
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||||
import app.revanced.util.fingerprint.definingClassOrThrow
|
import app.revanced.util.fingerprint.definingClassOrThrow
|
||||||
|
import app.revanced.util.fingerprint.matchOrThrow
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
|
||||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||||
"$GENERAL_PATH/LayoutSwitchPatch;"
|
"$GENERAL_PATH/ChangeFormFactorPatch;"
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
val layoutSwitchPatch = bytecodePatch(
|
val changeFormFactorPatch = bytecodePatch(
|
||||||
CHANGE_LAYOUT.title,
|
CHANGE_FORM_FACTOR.title,
|
||||||
CHANGE_LAYOUT.summary,
|
CHANGE_FORM_FACTOR.summary,
|
||||||
) {
|
) {
|
||||||
compatibleWith(COMPATIBLE_PACKAGE)
|
compatibleWith(COMPATIBLE_PACKAGE)
|
||||||
|
|
||||||
dependsOn(settingsPatch)
|
dependsOn(
|
||||||
|
settingsPatch,
|
||||||
|
playerTypeHookPatch,
|
||||||
|
navigationBarHookPatch,
|
||||||
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
|
||||||
@ -53,8 +60,9 @@ val layoutSwitchPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
layoutSwitchFingerprint.methodOrThrow().apply {
|
widthDpUIFingerprint.matchOrThrow().let {
|
||||||
val index = indexOfFirstInstructionReversedOrThrow(Opcode.IF_NEZ)
|
it.method.apply {
|
||||||
|
val index = it.patternMatch!!.startIndex
|
||||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
@ -64,6 +72,9 @@ val layoutSwitchPatch = bytecodePatch(
|
|||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hookNavigationButtonCreated(EXTENSION_CLASS_DESCRIPTOR)
|
||||||
|
|
||||||
// region add settings
|
// region add settings
|
||||||
|
|
||||||
@ -71,9 +82,9 @@ val layoutSwitchPatch = bytecodePatch(
|
|||||||
arrayOf(
|
arrayOf(
|
||||||
"PREFERENCE_SCREEN: GENERAL",
|
"PREFERENCE_SCREEN: GENERAL",
|
||||||
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS",
|
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS",
|
||||||
"SETTINGS: CHANGE_LAYOUT"
|
"SETTINGS: CHANGE_FORM_FACTOR"
|
||||||
),
|
),
|
||||||
CHANGE_LAYOUT
|
CHANGE_FORM_FACTOR
|
||||||
)
|
)
|
||||||
|
|
||||||
// endregion
|
// endregion
|
@ -1,4 +1,4 @@
|
|||||||
package app.revanced.patches.youtube.general.layoutswitch
|
package app.revanced.patches.youtube.general.formfactor
|
||||||
|
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.or
|
import app.revanced.util.or
|
||||||
@ -11,20 +11,16 @@ internal val formFactorEnumConstructorFingerprint = legacyFingerprint(
|
|||||||
strings = listOf(
|
strings = listOf(
|
||||||
"UNKNOWN_FORM_FACTOR",
|
"UNKNOWN_FORM_FACTOR",
|
||||||
"SMALL_FORM_FACTOR",
|
"SMALL_FORM_FACTOR",
|
||||||
"LARGE_FORM_FACTOR"
|
"LARGE_FORM_FACTOR",
|
||||||
|
"AUTOMOTIVE_FORM_FACTOR",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val layoutSwitchFingerprint = legacyFingerprint(
|
internal val widthDpUIFingerprint = legacyFingerprint(
|
||||||
name = "layoutSwitchFingerprint",
|
name = "widthDpUIFingerprint",
|
||||||
returnType = "I",
|
returnType = "I",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
parameters = listOf("L"),
|
|
||||||
opcodes = listOf(
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
|
||||||
Opcode.INVOKE_STATIC,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
Opcode.IF_NEZ,
|
Opcode.IF_NEZ,
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.RETURN,
|
Opcode.RETURN,
|
||||||
@ -41,6 +37,11 @@ internal val layoutSwitchFingerprint = legacyFingerprint(
|
|||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.RETURN,
|
Opcode.RETURN,
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.RETURN
|
Opcode.RETURN,
|
||||||
|
),
|
||||||
|
literals = listOf(
|
||||||
|
480L,
|
||||||
|
600L,
|
||||||
|
720L
|
||||||
)
|
)
|
||||||
)
|
)
|
@ -91,7 +91,25 @@ internal val createSearchSuggestionsFingerprint = legacyFingerprint(
|
|||||||
returnType = "Landroid/view/View;",
|
returnType = "Landroid/view/View;",
|
||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("I", "Landroid/view/View;", "Landroid/view/ViewGroup;"),
|
parameters = listOf("I", "Landroid/view/View;", "Landroid/view/ViewGroup;"),
|
||||||
strings = listOf("ss_rds")
|
strings = listOf("ss_rds"),
|
||||||
|
customFingerprint = { method, _ ->
|
||||||
|
indexOfIteratorInstruction(method) >= 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun indexOfIteratorInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstructionReversed {
|
||||||
|
opcode == Opcode.INVOKE_INTERFACE &&
|
||||||
|
getReference<MethodReference>()?.toString() == "Ljava/util/Iterator;->next()Ljava/lang/Object;"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flag is present in YouTube 19.16, but was not used until YouTube 19.43.
|
||||||
|
// Related issue: https://github.com/inotia00/ReVanced_Extended/issues/2784
|
||||||
|
internal const val SEARCH_FRAGMENT_FEATURE_FLAG = 45353159L
|
||||||
|
|
||||||
|
internal val searchFragmentFeatureFlagFingerprint = legacyFingerprint(
|
||||||
|
name = "searchFragmentFeatureFlagFingerprint",
|
||||||
|
literals = listOf(SEARCH_FRAGMENT_FEATURE_FLAG),
|
||||||
)
|
)
|
||||||
|
|
||||||
internal val drawerContentViewConstructorFingerprint = legacyFingerprint(
|
internal val drawerContentViewConstructorFingerprint = legacyFingerprint(
|
||||||
|
@ -15,7 +15,7 @@ import app.revanced.patches.youtube.utils.castbutton.hookToolBarCastButton
|
|||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
|
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_CLASS_DESCRIPTOR
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.TOOLBAR_COMPONENTS
|
import app.revanced.patches.youtube.utils.patch.PatchList.TOOLBAR_COMPONENTS
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_46_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_16_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.resourceid.actionBarRingoBackground
|
import app.revanced.patches.youtube.utils.resourceid.actionBarRingoBackground
|
||||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||||
@ -31,6 +31,7 @@ import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT
|
|||||||
import app.revanced.util.doRecursively
|
import app.revanced.util.doRecursively
|
||||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||||
import app.revanced.util.findMethodOrThrow
|
import app.revanced.util.findMethodOrThrow
|
||||||
|
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
|
||||||
import app.revanced.util.fingerprint.matchOrThrow
|
import app.revanced.util.fingerprint.matchOrThrow
|
||||||
import app.revanced.util.fingerprint.methodCall
|
import app.revanced.util.fingerprint.methodCall
|
||||||
import app.revanced.util.fingerprint.methodOrThrow
|
import app.revanced.util.fingerprint.methodOrThrow
|
||||||
@ -38,7 +39,6 @@ import app.revanced.util.fingerprint.mutableClassOrThrow
|
|||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.getWalkerMethod
|
import app.revanced.util.getWalkerMethod
|
||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
|
||||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
import app.revanced.util.replaceLiteralInstructionCall
|
import app.revanced.util.replaceLiteralInstructionCall
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
@ -46,6 +46,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
|||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
@ -266,36 +267,39 @@ val toolBarComponentsPatch = bytecodePatch(
|
|||||||
// region patch for hide search term thumbnail
|
// region patch for hide search term thumbnail
|
||||||
|
|
||||||
createSearchSuggestionsFingerprint.methodOrThrow().apply {
|
createSearchSuggestionsFingerprint.methodOrThrow().apply {
|
||||||
val literal = if (is_19_46_or_greater)
|
val iteratorIndex = indexOfIteratorInstruction(this)
|
||||||
32L
|
val replaceIndex = indexOfFirstInstructionOrThrow(iteratorIndex) {
|
||||||
else
|
opcode == Opcode.IGET_OBJECT &&
|
||||||
40L
|
getReference<FieldReference>()?.type == "Landroid/widget/ImageView;"
|
||||||
val relativeIndex = indexOfFirstLiteralInstructionOrThrow(literal)
|
}
|
||||||
val replaceIndex = indexOfFirstInstructionReversedOrThrow(relativeIndex) {
|
val jumpIndex = indexOfFirstInstructionOrThrow(replaceIndex) {
|
||||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
|
||||||
getReference<MethodReference>()?.toString() == "Landroid/widget/ImageView;->setVisibility(I)V"
|
|
||||||
} - 1
|
|
||||||
|
|
||||||
val jumpIndex = indexOfFirstInstructionOrThrow(relativeIndex) {
|
|
||||||
opcode == Opcode.INVOKE_STATIC &&
|
opcode == Opcode.INVOKE_STATIC &&
|
||||||
getReference<MethodReference>()?.toString() == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"
|
getReference<MethodReference>()?.toString() == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"
|
||||||
} + 4
|
} + 4
|
||||||
|
|
||||||
val replaceIndexInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
|
val replaceIndexInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
|
||||||
|
val freeRegister = replaceIndexInstruction.registerA
|
||||||
|
val classRegister = replaceIndexInstruction.registerB
|
||||||
val replaceIndexReference =
|
val replaceIndexReference =
|
||||||
getInstruction<ReferenceInstruction>(replaceIndex).reference
|
getInstruction<ReferenceInstruction>(replaceIndex).reference
|
||||||
|
|
||||||
addInstructionsWithLabels(
|
addInstructionsWithLabels(
|
||||||
replaceIndex + 1, """
|
replaceIndex + 1, """
|
||||||
invoke-static { }, $GENERAL_CLASS_DESCRIPTOR->hideSearchTermThumbnail()Z
|
invoke-static { }, $GENERAL_CLASS_DESCRIPTOR->hideSearchTermThumbnail()Z
|
||||||
move-result v${replaceIndexInstruction.registerA}
|
move-result v$freeRegister
|
||||||
if-nez v${replaceIndexInstruction.registerA}, :hidden
|
if-nez v$freeRegister, :hidden
|
||||||
iget-object v${replaceIndexInstruction.registerA}, v${replaceIndexInstruction.registerB}, $replaceIndexReference
|
iget-object v$freeRegister, v$classRegister, $replaceIndexReference
|
||||||
""", ExternalLabel("hidden", getInstruction(jumpIndex))
|
""", ExternalLabel("hidden", getInstruction(jumpIndex))
|
||||||
)
|
)
|
||||||
removeInstruction(replaceIndex)
|
removeInstruction(replaceIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_19_16_or_greater) {
|
||||||
|
searchFragmentFeatureFlagFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
SEARCH_FRAGMENT_FEATURE_FLAG,
|
||||||
|
"$GENERAL_CLASS_DESCRIPTOR->hideSearchTermThumbnail(Z)Z"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4,12 +4,14 @@ import app.revanced.patcher.patch.booleanOption
|
|||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
import app.revanced.patcher.patch.stringOption
|
import app.revanced.patcher.patch.stringOption
|
||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||||
|
import app.revanced.patches.youtube.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE
|
import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_32_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_32_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusIcon
|
import app.revanced.patches.youtube.utils.settings.ResourceUtils.updatePatchStatusIcon
|
||||||
|
import app.revanced.patches.youtube.utils.settings.getBytecodeContext
|
||||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||||
import app.revanced.util.ResourceGroup
|
import app.revanced.util.ResourceGroup
|
||||||
import app.revanced.util.Utils.printWarn
|
import app.revanced.util.Utils.printWarn
|
||||||
@ -19,6 +21,7 @@ import app.revanced.util.copyFile
|
|||||||
import app.revanced.util.copyResources
|
import app.revanced.util.copyResources
|
||||||
import app.revanced.util.getResourceGroup
|
import app.revanced.util.getResourceGroup
|
||||||
import app.revanced.util.underBarOrThrow
|
import app.revanced.util.underBarOrThrow
|
||||||
|
import app.revanced.util.updatePatchStatus
|
||||||
import app.revanced.util.valueOrThrow
|
import app.revanced.util.valueOrThrow
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
@ -247,11 +250,17 @@ val customBrandingIconPatch = resourcePatch(
|
|||||||
resourcesNode.appendChild(style)
|
resourcesNode.appendChild(style)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBytecodeContext().apply {
|
||||||
|
updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "OldSplashAnimation")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePatchStatusIcon(appIcon)
|
updatePatchStatusIcon(appIcon)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included = true
|
||||||
|
|
||||||
// region fix app icon
|
// region fix app icon
|
||||||
|
|
||||||
if (!is_19_34_or_greater) {
|
if (!is_19_34_or_greater) {
|
||||||
|
@ -123,7 +123,7 @@ val seekbarComponentsPatch = bytecodePatch(
|
|||||||
execute {
|
execute {
|
||||||
|
|
||||||
val restoreOldSplashAnimationIncluded = CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true &&
|
val restoreOldSplashAnimationIncluded = CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true &&
|
||||||
customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimationOption").value == true
|
customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimation").value == true
|
||||||
|
|
||||||
var settingArray = arrayOf(
|
var settingArray = arrayOf(
|
||||||
"PREFERENCE_SCREEN: PLAYER",
|
"PREFERENCE_SCREEN: PLAYER",
|
||||||
@ -388,7 +388,7 @@ val seekbarComponentsPatch = bytecodePatch(
|
|||||||
scaleNode.replaceChild(replacementNode, shapeNode)
|
scaleNode.replaceChild(replacementNode, shapeNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_19_25_or_greater && !restoreOldSplashAnimationIncluded) {
|
if (is_19_25_or_greater) {
|
||||||
// Add attribute and styles for splash screen custom color.
|
// Add attribute and styles for splash screen custom color.
|
||||||
// Using a style is the only way to selectively change just the seekbar fill color.
|
// Using a style is the only way to selectively change just the seekbar fill color.
|
||||||
//
|
//
|
||||||
|
@ -234,7 +234,8 @@ internal val youtubeControlsOverlayFingerprint = legacyFingerprint(
|
|||||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||||
parameters = emptyList(),
|
parameters = emptyList(),
|
||||||
literals = listOf(
|
literals = listOf(
|
||||||
fadeDurationFast,
|
// Removed in YouTube 20.09.40+
|
||||||
|
// fadeDurationFast,
|
||||||
insetOverlayViewLayout,
|
insetOverlayViewLayout,
|
||||||
scrimOverlay,
|
scrimOverlay,
|
||||||
// Removed in YouTube 20.02.38+
|
// Removed in YouTube 20.02.38+
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
package app.revanced.patches.youtube.utils.fix.splash
|
package app.revanced.patches.youtube.utils.fix.splash
|
||||||
|
|
||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
|
import app.revanced.patches.youtube.layout.branding.icon.customBrandingIconPatch
|
||||||
|
import app.revanced.patches.youtube.utils.patch.PatchList.CUSTOM_BRANDING_ICON_FOR_YOUTUBE
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_32_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_32_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
|
import app.revanced.util.getBooleanOptionValue
|
||||||
import org.w3c.dom.Element
|
import org.w3c.dom.Element
|
||||||
|
|
||||||
val darkModeSplashScreenPatch = resourcePatch(
|
val darkModeSplashScreenPatch = resourcePatch(
|
||||||
@ -10,10 +13,10 @@ val darkModeSplashScreenPatch = resourcePatch(
|
|||||||
) {
|
) {
|
||||||
dependsOn(versionCheckPatch)
|
dependsOn(versionCheckPatch)
|
||||||
|
|
||||||
execute {
|
finalize {
|
||||||
if (!is_19_32_or_greater) {
|
val restoreOldSplashAnimationIncluded = is_19_32_or_greater &&
|
||||||
return@execute
|
CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true &&
|
||||||
}
|
customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimation").value == true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fix the splash screen dark mode background color.
|
* Fix the splash screen dark mode background color.
|
||||||
@ -24,6 +27,7 @@ val darkModeSplashScreenPatch = resourcePatch(
|
|||||||
* This is a bug in unpatched YouTube.
|
* This is a bug in unpatched YouTube.
|
||||||
* Should always be applied even if the `Theme` patch is excluded.
|
* Should always be applied even if the `Theme` patch is excluded.
|
||||||
*/
|
*/
|
||||||
|
if (restoreOldSplashAnimationIncluded) {
|
||||||
document("res/values-night/styles.xml").use { document ->
|
document("res/values-night/styles.xml").use { document ->
|
||||||
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
||||||
val childNodes = resourcesNode.childNodes
|
val childNodes = resourcesNode.childNodes
|
||||||
@ -48,5 +52,32 @@ val darkModeSplashScreenPatch = resourcePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
document("res/values-night-v27/styles.xml").use { document ->
|
||||||
|
// Create a night mode specific override for the splash screen background.
|
||||||
|
val style = document.createElement("style")
|
||||||
|
style.setAttribute("name", "Theme.YouTube.Home")
|
||||||
|
style.setAttribute("parent", "@style/Base.V27.Theme.YouTube.Home")
|
||||||
|
|
||||||
|
// Fix status and navigation bar showing white on some Android devices,
|
||||||
|
// such as SDK 28 Android 10 medium tablet.
|
||||||
|
val colorSplashBackgroundColor = "@color/yt_black1"
|
||||||
|
arrayOf(
|
||||||
|
"android:navigationBarColor" to colorSplashBackgroundColor,
|
||||||
|
"android:windowBackground" to colorSplashBackgroundColor,
|
||||||
|
"android:colorBackground" to colorSplashBackgroundColor,
|
||||||
|
"colorPrimaryDark" to colorSplashBackgroundColor,
|
||||||
|
"android:windowLightStatusBar" to "false",
|
||||||
|
).forEach { (name, value) ->
|
||||||
|
val styleItem = document.createElement("item")
|
||||||
|
styleItem.setAttribute("name", name)
|
||||||
|
styleItem.textContent = value
|
||||||
|
style.appendChild(styleItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
||||||
|
resourcesNode.appendChild(style)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,4 +146,10 @@ internal val onesieEncryptionFeatureFlagFingerprint = legacyFingerprint(
|
|||||||
literals = listOf(ONESIE_ENCRYPTION_FEATURE_FLAG),
|
literals = listOf(ONESIE_ENCRYPTION_FEATURE_FLAG),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// YouTube 20.10 ~
|
||||||
|
internal const val ONESIE_ENCRYPTION_ALTERNATIVE_FEATURE_FLAG = 45683169L
|
||||||
|
|
||||||
|
internal val onesieEncryptionAlternativeFeatureFlagFingerprint = legacyFingerprint(
|
||||||
|
name = "onesieEncryptionAlternativeFeatureFlagFingerprint",
|
||||||
|
literals = listOf(ONESIE_ENCRYPTION_ALTERNATIVE_FEATURE_FLAG),
|
||||||
|
)
|
||||||
|
@ -19,6 +19,7 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC
|
|||||||
import app.revanced.patches.youtube.utils.compatibility.Constants.YOUTUBE_PACKAGE_NAME
|
import app.revanced.patches.youtube.utils.compatibility.Constants.YOUTUBE_PACKAGE_NAME
|
||||||
import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_STREAMING_DATA
|
import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_STREAMING_DATA
|
||||||
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
import app.revanced.patches.youtube.utils.playservice.is_19_34_or_greater
|
||||||
|
import app.revanced.patches.youtube.utils.playservice.is_20_10_or_greater
|
||||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||||
import app.revanced.patches.youtube.utils.request.buildRequestPatch
|
import app.revanced.patches.youtube.utils.request.buildRequestPatch
|
||||||
import app.revanced.patches.youtube.utils.request.hookBuildRequest
|
import app.revanced.patches.youtube.utils.request.hookBuildRequest
|
||||||
@ -61,6 +62,10 @@ val spoofStreamingDataPatch = bytecodePatch(
|
|||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
|
||||||
|
var settingArray = arrayOf(
|
||||||
|
"SETTINGS: SPOOF_STREAMING_DATA"
|
||||||
|
)
|
||||||
|
|
||||||
// region Get replacement streams at player requests.
|
// region Get replacement streams at player requests.
|
||||||
|
|
||||||
hookBuildRequest("$EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V")
|
hookBuildRequest("$EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V")
|
||||||
@ -327,6 +332,15 @@ val spoofStreamingDataPatch = bytecodePatch(
|
|||||||
ONESIE_ENCRYPTION_FEATURE_FLAG,
|
ONESIE_ENCRYPTION_FEATURE_FLAG,
|
||||||
"$EXTENSION_CLASS_DESCRIPTOR->skipResponseEncryption(Z)Z"
|
"$EXTENSION_CLASS_DESCRIPTOR->skipResponseEncryption(Z)Z"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (is_20_10_or_greater) {
|
||||||
|
onesieEncryptionAlternativeFeatureFlagFingerprint.injectLiteralInstructionBooleanCall(
|
||||||
|
ONESIE_ENCRYPTION_ALTERNATIVE_FEATURE_FLAG,
|
||||||
|
"$EXTENSION_CLASS_DESCRIPTOR->skipResponseEncryption(Z)Z"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
settingArray += "SETTINGS: SKIP_RESPONSE_ENCRYPTION"
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@ -339,9 +353,7 @@ val spoofStreamingDataPatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
addPreference(
|
addPreference(
|
||||||
arrayOf(
|
settingArray,
|
||||||
"SETTINGS: SPOOF_STREAMING_DATA"
|
|
||||||
),
|
|
||||||
SPOOF_STREAMING_DATA
|
SPOOF_STREAMING_DATA
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,7 @@ val navigationBarHookPatch = bytecodePatch(
|
|||||||
hookNavigationButtonCreated = { extensionClassDescriptor ->
|
hookNavigationButtonCreated = { extensionClassDescriptor ->
|
||||||
navigationBarHookCallbackFingerprint.methodOrThrow().addInstruction(
|
navigationBarHookCallbackFingerprint.methodOrThrow().addInstruction(
|
||||||
0,
|
0,
|
||||||
"invoke-static { p0, p1 }, " +
|
"invoke-static { p0, p1 }, $extensionClassDescriptor->navigationTabCreated" +
|
||||||
"$extensionClassDescriptor->navigationTabCreated" +
|
|
||||||
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
|
"(${EXTENSION_NAVIGATION_BUTTON_DESCRIPTOR}Landroid/view/View;)V",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,9 @@ internal enum class PatchList(
|
|||||||
"Bypass URL redirects",
|
"Bypass URL redirects",
|
||||||
"Adds an option to bypass URL redirects and open the original URL directly."
|
"Adds an option to bypass URL redirects and open the original URL directly."
|
||||||
),
|
),
|
||||||
CHANGE_LAYOUT(
|
CHANGE_FORM_FACTOR(
|
||||||
"Change layout",
|
"Change form factor",
|
||||||
"Adds an option to change the dp in order to use a tablet or phone layout."
|
"Adds an option to change the UI appearance to a phone, tablet, or automotive device."
|
||||||
),
|
),
|
||||||
CHANGE_LIVE_RING_CLICK_ACTION(
|
CHANGE_LIVE_RING_CLICK_ACTION(
|
||||||
"Change live ring click action",
|
"Change live ring click action",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app.revanced.patches.youtube.utils.playertype
|
package app.revanced.patches.youtube.utils.playertype
|
||||||
|
|
||||||
import app.revanced.patches.youtube.utils.resourceid.reelWatchPlayer
|
import app.revanced.patches.youtube.utils.resourceid.reelWatchPlayer
|
||||||
|
import app.revanced.patches.youtube.utils.resourceid.toolbarContainerId
|
||||||
import app.revanced.util.fingerprint.legacyFingerprint
|
import app.revanced.util.fingerprint.legacyFingerprint
|
||||||
import app.revanced.util.getReference
|
import app.revanced.util.getReference
|
||||||
import app.revanced.util.indexOfFirstInstruction
|
import app.revanced.util.indexOfFirstInstruction
|
||||||
@ -9,6 +10,7 @@ import com.android.tools.smali.dexlib2.AccessFlags
|
|||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
import com.android.tools.smali.dexlib2.iface.Method
|
import com.android.tools.smali.dexlib2.iface.Method
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||||
|
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
|
||||||
|
|
||||||
internal val browseIdClassFingerprint = legacyFingerprint(
|
internal val browseIdClassFingerprint = legacyFingerprint(
|
||||||
name = "browseIdClassFingerprint",
|
name = "browseIdClassFingerprint",
|
||||||
@ -61,6 +63,34 @@ internal val searchQueryClassFingerprint = legacyFingerprint(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
internal val toolbarLayoutFingerprint = legacyFingerprint(
|
||||||
|
name = "toolbarLayoutFingerprint",
|
||||||
|
literals = listOf(toolbarContainerId),
|
||||||
|
customFingerprint = { method, _ ->
|
||||||
|
method.name == "<init>" &&
|
||||||
|
indexOfMainCollapsingToolbarLayoutInstruction(method) >= 0
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun indexOfMainCollapsingToolbarLayoutInstruction(method: Method) =
|
||||||
|
method.indexOfFirstInstruction {
|
||||||
|
opcode == Opcode.CHECK_CAST &&
|
||||||
|
getReference<TypeReference>()?.type == "Lcom/google/android/apps/youtube/app/ui/actionbar/MainCollapsingToolbarLayout;"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches to https://android.googlesource.com/platform/frameworks/support/+/9eee6ba/v7/appcompat/src/android/support/v7/widget/Toolbar.java#963
|
||||||
|
*/
|
||||||
|
internal val appCompatToolbarBackButtonFingerprint = legacyFingerprint(
|
||||||
|
name = "appCompatToolbarBackButtonFingerprint",
|
||||||
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
returnType = "Landroid/graphics/drawable/Drawable;",
|
||||||
|
parameters = emptyList(),
|
||||||
|
customFingerprint = { _, classDef ->
|
||||||
|
classDef.type == "Landroid/support/v7/widget/Toolbar;"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
internal val videoStateFingerprint = legacyFingerprint(
|
internal val videoStateFingerprint = legacyFingerprint(
|
||||||
name = "videoStateFingerprint",
|
name = "videoStateFingerprint",
|
||||||
returnType = "V",
|
returnType = "V",
|
||||||
|
@ -5,6 +5,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
|||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
import app.revanced.patcher.patch.PatchException
|
import app.revanced.patcher.patch.PatchException
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patches.shared.litho.addLithoFilter
|
import app.revanced.patches.shared.litho.addLithoFilter
|
||||||
import app.revanced.patches.shared.litho.lithoFilterPatch
|
import app.revanced.patches.shared.litho.lithoFilterPatch
|
||||||
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
|
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
|
||||||
@ -21,10 +22,13 @@ import app.revanced.util.getReference
|
|||||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||||
|
import com.android.tools.smali.dexlib2.AccessFlags
|
||||||
import com.android.tools.smali.dexlib2.Opcode
|
import com.android.tools.smali.dexlib2.Opcode
|
||||||
|
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||||
|
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||||
|
|
||||||
private const val EXTENSION_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR =
|
private const val EXTENSION_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR =
|
||||||
"$UTILS_PATH/PlayerTypeHookPatch;"
|
"$UTILS_PATH/PlayerTypeHookPatch;"
|
||||||
@ -32,6 +36,9 @@ private const val EXTENSION_PLAYER_TYPE_HOOK_CLASS_DESCRIPTOR =
|
|||||||
private const val EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR =
|
private const val EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR =
|
||||||
"$SHARED_PATH/RootView;"
|
"$SHARED_PATH/RootView;"
|
||||||
|
|
||||||
|
private const val EXTENSION_ROOT_VIEW_TOOLBAR_INTERFACE =
|
||||||
|
"$SHARED_PATH/RootView${'$'}AppCompatToolbarPatchInterface;"
|
||||||
|
|
||||||
private const val FILTER_CLASS_DESCRIPTOR =
|
private const val FILTER_CLASS_DESCRIPTOR =
|
||||||
"$COMPONENTS_PATH/RelatedVideoFilter;"
|
"$COMPONENTS_PATH/RelatedVideoFilter;"
|
||||||
|
|
||||||
@ -165,6 +172,53 @@ val playerTypeHookPatch = bytecodePatch(
|
|||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
|
// region patch for hook back button visibility
|
||||||
|
|
||||||
|
toolbarLayoutFingerprint.methodOrThrow().apply {
|
||||||
|
val index = indexOfMainCollapsingToolbarLayoutInstruction(this)
|
||||||
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
|
addInstruction(
|
||||||
|
index + 1,
|
||||||
|
"invoke-static { v$register }, $EXTENSION_ROOT_VIEW_HOOK_CLASS_DESCRIPTOR->setToolbar(Landroid/widget/FrameLayout;)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add interface for extensions code to call obfuscated methods.
|
||||||
|
appCompatToolbarBackButtonFingerprint.matchOrThrow().let {
|
||||||
|
it.classDef.apply {
|
||||||
|
interfaces.add(EXTENSION_ROOT_VIEW_TOOLBAR_INTERFACE)
|
||||||
|
|
||||||
|
val definingClass = type
|
||||||
|
val obfuscatedMethodName = it.originalMethod.name
|
||||||
|
val returnType = "Landroid/graphics/drawable/Drawable;"
|
||||||
|
|
||||||
|
methods.add(
|
||||||
|
ImmutableMethod(
|
||||||
|
definingClass,
|
||||||
|
"patch_getToolbarIcon",
|
||||||
|
listOf(),
|
||||||
|
returnType,
|
||||||
|
AccessFlags.PUBLIC.value or AccessFlags.FINAL.value,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
MutableMethodImplementation(2),
|
||||||
|
).toMutable().apply {
|
||||||
|
addInstructions(
|
||||||
|
0,
|
||||||
|
"""
|
||||||
|
invoke-virtual { p0 }, $definingClass->$obfuscatedMethodName()$returnType
|
||||||
|
move-result-object v0
|
||||||
|
return-object v0
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
|
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,8 @@ var is_19_09_or_greater = false
|
|||||||
private set
|
private set
|
||||||
var is_19_15_or_greater = false
|
var is_19_15_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
var is_19_16_or_greater = false
|
||||||
|
private set
|
||||||
var is_19_17_or_greater = false
|
var is_19_17_or_greater = false
|
||||||
private set
|
private set
|
||||||
var is_19_23_or_greater = false
|
var is_19_23_or_greater = false
|
||||||
@ -59,6 +61,8 @@ var is_20_03_or_greater = false
|
|||||||
private set
|
private set
|
||||||
var is_20_05_or_greater = false
|
var is_20_05_or_greater = false
|
||||||
private set
|
private set
|
||||||
|
var is_20_10_or_greater = false
|
||||||
|
private set
|
||||||
|
|
||||||
val versionCheckPatch = resourcePatch(
|
val versionCheckPatch = resourcePatch(
|
||||||
description = "versionCheckPatch",
|
description = "versionCheckPatch",
|
||||||
@ -83,6 +87,7 @@ val versionCheckPatch = resourcePatch(
|
|||||||
is_19_04_or_greater = 240502000 <= playStoreServicesVersion
|
is_19_04_or_greater = 240502000 <= playStoreServicesVersion
|
||||||
is_19_09_or_greater = 241002000 <= playStoreServicesVersion
|
is_19_09_or_greater = 241002000 <= playStoreServicesVersion
|
||||||
is_19_15_or_greater = 241602000 <= playStoreServicesVersion
|
is_19_15_or_greater = 241602000 <= playStoreServicesVersion
|
||||||
|
is_19_16_or_greater = 241702000 <= playStoreServicesVersion
|
||||||
is_19_17_or_greater = 241802000 <= playStoreServicesVersion
|
is_19_17_or_greater = 241802000 <= playStoreServicesVersion
|
||||||
is_19_23_or_greater = 242402000 <= playStoreServicesVersion
|
is_19_23_or_greater = 242402000 <= playStoreServicesVersion
|
||||||
is_19_25_or_greater = 242599000 <= playStoreServicesVersion
|
is_19_25_or_greater = 242599000 <= playStoreServicesVersion
|
||||||
@ -101,5 +106,6 @@ val versionCheckPatch = resourcePatch(
|
|||||||
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
|
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
|
||||||
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
|
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
|
||||||
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
|
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
|
||||||
|
is_20_10_or_greater = 251105000 <= playStoreServicesVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,6 +213,8 @@ var tapBloomView = -1L
|
|||||||
private set
|
private set
|
||||||
var titleAnchor = -1L
|
var titleAnchor = -1L
|
||||||
private set
|
private set
|
||||||
|
var toolbarContainerId = -1L
|
||||||
|
private set
|
||||||
var toolTipContentView = -1L
|
var toolTipContentView = -1L
|
||||||
private set
|
private set
|
||||||
var totalTime = -1L
|
var totalTime = -1L
|
||||||
@ -656,6 +658,10 @@ internal val sharedResourceIdPatch = resourcePatch(
|
|||||||
ID,
|
ID,
|
||||||
"title_anchor"
|
"title_anchor"
|
||||||
]
|
]
|
||||||
|
toolbarContainerId = resourceMappings[
|
||||||
|
ID,
|
||||||
|
"toolbar_container"
|
||||||
|
]
|
||||||
toolTipContentView = resourceMappings[
|
toolTipContentView = resourceMappings[
|
||||||
LAYOUT,
|
LAYOUT,
|
||||||
"tooltip_content_view"
|
"tooltip_content_view"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package app.revanced.patches.youtube.utils.settings
|
package app.revanced.patches.youtube.utils.settings
|
||||||
|
|
||||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||||
|
import app.revanced.patcher.patch.BytecodePatchContext
|
||||||
import app.revanced.patcher.patch.bytecodePatch
|
import app.revanced.patcher.patch.bytecodePatch
|
||||||
import app.revanced.patcher.patch.resourcePatch
|
import app.revanced.patcher.patch.resourcePatch
|
||||||
import app.revanced.patcher.patch.stringOption
|
import app.revanced.patcher.patch.stringOption
|
||||||
@ -39,6 +40,10 @@ private const val EXTENSION_INITIALIZATION_CLASS_DESCRIPTOR =
|
|||||||
private const val EXTENSION_THEME_METHOD_DESCRIPTOR =
|
private const val EXTENSION_THEME_METHOD_DESCRIPTOR =
|
||||||
"$EXTENSION_UTILS_PATH/BaseThemeUtils;->setTheme(Ljava/lang/Enum;)V"
|
"$EXTENSION_UTILS_PATH/BaseThemeUtils;->setTheme(Ljava/lang/Enum;)V"
|
||||||
|
|
||||||
|
private lateinit var bytecodeContext: BytecodePatchContext
|
||||||
|
|
||||||
|
internal fun getBytecodeContext() = bytecodeContext
|
||||||
|
|
||||||
private val settingsBytecodePatch = bytecodePatch(
|
private val settingsBytecodePatch = bytecodePatch(
|
||||||
description = "settingsBytecodePatch"
|
description = "settingsBytecodePatch"
|
||||||
) {
|
) {
|
||||||
@ -50,6 +55,7 @@ private val settingsBytecodePatch = bytecodePatch(
|
|||||||
)
|
)
|
||||||
|
|
||||||
execute {
|
execute {
|
||||||
|
bytecodeContext = this
|
||||||
|
|
||||||
// apply the current theme of the settings page
|
// apply the current theme of the settings page
|
||||||
themeSetterSystemFingerprint.methodOrThrow().apply {
|
themeSetterSystemFingerprint.methodOrThrow().apply {
|
||||||
|
@ -10,7 +10,6 @@ private val PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST = listOf(
|
|||||||
"[B",
|
"[B",
|
||||||
"Ljava/lang/String;", // Player parameters proto buffer.
|
"Ljava/lang/String;", // Player parameters proto buffer.
|
||||||
"Ljava/lang/String;", // PlaylistId.
|
"Ljava/lang/String;", // PlaylistId.
|
||||||
"I",
|
|
||||||
"I"
|
"I"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -19,7 +18,7 @@ internal val playerParameterBuilderFingerprint = legacyFingerprint(
|
|||||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
returnType = "L",
|
returnType = "L",
|
||||||
strings = listOf("psps"),
|
strings = listOf("psps"),
|
||||||
// 19.22 and earlier parameters are:
|
// parameters in 18.29 ~ 19.22 :
|
||||||
// "Ljava/lang/String;", // VideoId.
|
// "Ljava/lang/String;", // VideoId.
|
||||||
// "[B",
|
// "[B",
|
||||||
// "Ljava/lang/String;", // Player parameters proto buffer.
|
// "Ljava/lang/String;", // Player parameters proto buffer.
|
||||||
@ -34,20 +33,39 @@ internal val playerParameterBuilderFingerprint = legacyFingerprint(
|
|||||||
// "Z",
|
// "Z",
|
||||||
// "Z"
|
// "Z"
|
||||||
|
|
||||||
// 19.23+ parameters are:
|
// parameters in 19.23 ~ 20.09 :
|
||||||
// "Ljava/lang/String;", // VideoId.
|
// "Ljava/lang/String;", // VideoId.
|
||||||
// "[B",
|
// "[B",
|
||||||
// "Ljava/lang/String;", // Player parameters proto buffer.
|
// "Ljava/lang/String;", // Player parameters proto buffer.
|
||||||
// "Ljava/lang/String;", // PlaylistId.
|
// "Ljava/lang/String;", // PlaylistId.
|
||||||
// "I",
|
// "I",
|
||||||
// "I",
|
// "I",
|
||||||
// "L",
|
// "L", // New parameters added in 19.25.
|
||||||
// "Ljava/util/Set;",
|
// "Ljava/util/Set;",
|
||||||
// "Ljava/lang/String;",
|
// "Ljava/lang/String;",
|
||||||
// "Ljava/lang/String;",
|
// "Ljava/lang/String;",
|
||||||
// "L",
|
// "L",
|
||||||
// "Z", // Appears to indicate if the video id is being opened or is currently playing.
|
// "Z", // Appears to indicate if the video id is being opened or is currently playing.
|
||||||
// "Z",
|
// "Z",
|
||||||
|
// "Z",
|
||||||
|
// "Z"
|
||||||
|
|
||||||
|
// parameters in 20.10 ~ :
|
||||||
|
// "Ljava/lang/String;", // VideoId.
|
||||||
|
// "[B",
|
||||||
|
// "Ljava/lang/String;", // Player parameters proto buffer.
|
||||||
|
// "Ljava/lang/String;", // PlaylistId.
|
||||||
|
// "I",
|
||||||
|
// "Z", // New parameters added in 20.10.
|
||||||
|
// "I",
|
||||||
|
// "L", // New parameters added in 19.25.
|
||||||
|
// "Ljava/util/Set;",
|
||||||
|
// "Ljava/lang/String;",
|
||||||
|
// "Ljava/lang/String;",
|
||||||
|
// "L",
|
||||||
|
// "Z", // Appears to indicate if the video id is being opened or is currently playing.
|
||||||
|
// "Z",
|
||||||
|
// "Z",
|
||||||
// "Z"
|
// "Z"
|
||||||
customFingerprint = custom@{ method, _ ->
|
customFingerprint = custom@{ method, _ ->
|
||||||
val parameterTypes = method.parameterTypes
|
val parameterTypes = method.parameterTypes
|
||||||
@ -56,7 +74,7 @@ internal val playerParameterBuilderFingerprint = legacyFingerprint(
|
|||||||
return@custom false
|
return@custom false
|
||||||
}
|
}
|
||||||
|
|
||||||
val startsWithMethodParameterList = parameterTypes.slice(0..5)
|
val startsWithMethodParameterList = parameterTypes.slice(0..4)
|
||||||
|
|
||||||
parametersEqual(
|
parametersEqual(
|
||||||
PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST,
|
PLAYER_PARAMETER_STARTS_WITH_PARAMETER_LIST,
|
||||||
|
@ -37,11 +37,18 @@ val playerResponseMethodHookPatch = bytecodePatch(
|
|||||||
?: playerParameterBuilderLegacyFingerprint.methodOrThrow()
|
?: playerParameterBuilderLegacyFingerprint.methodOrThrow()
|
||||||
|
|
||||||
playerResponseMethod.apply {
|
playerResponseMethod.apply {
|
||||||
parameterIsShortAndOpeningOrPlaying = parameterTypes.indexOfFirst { it == "Z" } + 1
|
val setIndex = parameterTypes.indexOfFirst { it == "Ljava/util/Set;" }
|
||||||
|
val parameterSize = parameterTypes.size
|
||||||
|
val relativeIndex = parameterTypes.subList(setIndex, parameterSize - 1).indexOfFirst { it == "Z" }
|
||||||
|
|
||||||
|
// YouTube 18.29 ~ 19.22 : p11
|
||||||
|
// YouTube 19.23 ~ 20.09 : p12
|
||||||
|
// YouTube 20.10 ~ : p13
|
||||||
|
parameterIsShortAndOpeningOrPlaying = setIndex + relativeIndex + 1
|
||||||
// On some app targets the method has too many registers pushing the parameters past v15.
|
// On some app targets the method has too many registers pushing the parameters past v15.
|
||||||
// If needed, move the parameters to 4-bit registers so they can be passed to extension.
|
// If needed, move the parameters to 4-bit registers so they can be passed to extension.
|
||||||
playerResponseMethodCopyRegisters = implementation!!.registerCount -
|
playerResponseMethodCopyRegisters = implementation!!.registerCount -
|
||||||
parameterTypes.size + parameterIsShortAndOpeningOrPlaying > 15
|
parameterSize + parameterIsShortAndOpeningOrPlaying > 15
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerResponseMethodCopyRegisters) {
|
if (playerResponseMethodCopyRegisters) {
|
||||||
|
@ -100,24 +100,24 @@ fun Pair<String, Fingerprint>.injectLiteralInstructionBooleanCall(
|
|||||||
) {
|
) {
|
||||||
methodOrThrow().apply {
|
methodOrThrow().apply {
|
||||||
val literalIndex = indexOfFirstLiteralInstruction(literal)
|
val literalIndex = indexOfFirstLiteralInstruction(literal)
|
||||||
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
|
val index = indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT)
|
||||||
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
|
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||||
|
|
||||||
val smaliInstruction =
|
val smaliInstruction =
|
||||||
if (descriptor.startsWith("0x")) """
|
if (descriptor.startsWith("0x")) """
|
||||||
const/16 v$targetRegister, $descriptor
|
const/16 v$register, $descriptor
|
||||||
"""
|
"""
|
||||||
else if (descriptor.endsWith("(Z)Z")) """
|
else if (descriptor.endsWith("(Z)Z")) """
|
||||||
invoke-static {v$targetRegister}, $descriptor
|
invoke-static/range { v$register .. v$register }, $descriptor
|
||||||
move-result v$targetRegister
|
move-result v$register
|
||||||
"""
|
"""
|
||||||
else """
|
else """
|
||||||
invoke-static {}, $descriptor
|
invoke-static {}, $descriptor
|
||||||
move-result v$targetRegister
|
move-result v$register
|
||||||
"""
|
"""
|
||||||
|
|
||||||
addInstructions(
|
addInstructions(
|
||||||
targetIndex + 1,
|
index + 1,
|
||||||
smaliInstruction
|
smaliInstruction
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@
|
|||||||
<item>@string/revanced_change_start_page_entry_liked_music</item>
|
<item>@string/revanced_change_start_page_entry_liked_music</item>
|
||||||
<item>@string/revanced_change_start_page_entry_podcasts</item>
|
<item>@string/revanced_change_start_page_entry_podcasts</item>
|
||||||
<item>@string/revanced_change_start_page_entry_samples</item>
|
<item>@string/revanced_change_start_page_entry_samples</item>
|
||||||
<item>@string/revanced_change_start_page_entry_search</item>
|
|
||||||
<item>@string/revanced_change_start_page_entry_subscriptions</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_change_start_page_entry_values">
|
<string-array name="revanced_change_start_page_entry_values">
|
||||||
<item>ORIGINAL</item>
|
<item>ORIGINAL</item>
|
||||||
@ -23,8 +21,6 @@
|
|||||||
<item>LIKED_MUSIC</item>
|
<item>LIKED_MUSIC</item>
|
||||||
<item>PODCASTS</item>
|
<item>PODCASTS</item>
|
||||||
<item>SAMPLES</item>
|
<item>SAMPLES</item>
|
||||||
<item>SEARCH</item>
|
|
||||||
<item>SUBSCRIPTIONS</item>
|
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="revanced_disable_music_video_in_album_redirect_type_entries">
|
<string-array name="revanced_disable_music_video_in_album_redirect_type_entries">
|
||||||
<item>@string/revanced_disable_music_video_in_album_redirect_type_entry_redirect</item>
|
<item>@string/revanced_disable_music_video_in_album_redirect_type_entry_redirect</item>
|
||||||
|
@ -231,6 +231,18 @@ This does not bypass the age restriction. It just accepts it automatically."</st
|
|||||||
<string name="revanced_hide_navigation_bar_summary">Hides the navigation bar.</string>
|
<string name="revanced_hide_navigation_bar_summary">Hides the navigation bar.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Hide navigation labels</string>
|
<string name="revanced_hide_navigation_label_title">Hide navigation labels</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Hides the label below each navigation button.</string>
|
<string name="revanced_hide_navigation_label_summary">Hides the label below each navigation button.</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">Replace Samples button</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">Replaces the Samples button with the Search button.</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">Replace Upgrade button</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">Replaces the Upgrade button with the Settings button.</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">About replace button</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"This feature is experimental.
|
||||||
|
There are structural limitations of the patch, as Activities such as Search and Settings in YouTube Music are not public.
|
||||||
|
|
||||||
|
Known issues:
|
||||||
|
• When a replaced Activity such as Search and Settings is closed, the start page opens.
|
||||||
|
|
||||||
|
Click to open the 'Change start page' settings."</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
@ -501,6 +513,11 @@ Info:
|
|||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">Spoof player parameter</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"Spoof the player parameter to prevent playback issues.
|
||||||
|
|
||||||
|
Side effect:
|
||||||
|
• Sometimes the subtitles are located at the top of the player instead of the bottom."</string>
|
||||||
<string name="revanced_watch_history_type_title">Watch history type</string>
|
<string name="revanced_watch_history_type_title">Watch history type</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• Original: Follows the watch history settings of Google account, but watch history may not work due to DNS or VPN.
|
<string name="revanced_watch_history_type_summary">"• Original: Follows the watch history settings of Google account, but watch history may not work due to DNS or VPN.
|
||||||
• Replace domain: Follows the watch history settings of Google account.
|
• Replace domain: Follows the watch history settings of Google account.
|
||||||
|
@ -451,6 +451,7 @@
|
|||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">Παραποίηση παραμέτρου προγράμματος αναπαραγωγής</string>
|
||||||
<string name="revanced_watch_history_type_title">Τύπος ιστορικού παρακολούθησης</string>
|
<string name="revanced_watch_history_type_title">Τύπος ιστορικού παρακολούθησης</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• Αρχικός: Ακολουθεί τις ρυθμίσεις ιστορικού παρακολούθησης του λογαριασμού Google σας, αλλά το ιστορικό παρακολούθησης μπορεί να μη λειτουργεί λόγω χρήσης VPN ή εναλλακτικού DNS.
|
<string name="revanced_watch_history_type_summary">"• Αρχικός: Ακολουθεί τις ρυθμίσεις ιστορικού παρακολούθησης του λογαριασμού Google σας, αλλά το ιστορικό παρακολούθησης μπορεί να μη λειτουργεί λόγω χρήσης VPN ή εναλλακτικού DNS.
|
||||||
• Αντικατάσταση του domain: Ακολουθεί τις ρυθμίσεις ιστορικού παρακολούθησης του λογαριασμού Google σας.
|
• Αντικατάσταση του domain: Ακολουθεί τις ρυθμίσεις ιστορικού παρακολούθησης του λογαριασμού Google σας.
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Shared -->
|
<!-- Shared -->
|
||||||
|
<string name="revanced_extended_settings_title">RVX</string>
|
||||||
<string name="revanced_extended_reset_to_default_toast">Restablecer a valores por defecto.</string>
|
<string name="revanced_extended_reset_to_default_toast">Restablecer a valores por defecto.</string>
|
||||||
<!-- Shared Category -->
|
<!-- Shared Category -->
|
||||||
<string name="revanced_extended_restart_first_run">Reiniciar para cargar el diseño normalmente</string>
|
<string name="revanced_extended_restart_first_run">Reiniciar para cargar el diseño normalmente</string>
|
||||||
@ -19,6 +20,8 @@
|
|||||||
<string name="revanced_hide_terms_container_summary">Oculta los términos del contenedor de servicio.</string>
|
<string name="revanced_hide_terms_container_summary">Oculta los términos del contenedor de servicio.</string>
|
||||||
<!-- PreferenceScreen: Action bar -->
|
<!-- PreferenceScreen: Action bar -->
|
||||||
<string name="revanced_preference_screen_action_bar_title">Barra de Acción</string>
|
<string name="revanced_preference_screen_action_bar_title">Barra de Acción</string>
|
||||||
|
<string name="revanced_change_action_bar_position_title">Cambiar posición de la barra de acción</string>
|
||||||
|
<string name="revanced_change_action_bar_position_summary">Mueve la barra de acción debajo del botón de reproducción.</string>
|
||||||
<string name="revanced_hide_action_button_like_dislike_title">Ocultar botones Me gusta y No me gusta</string>
|
<string name="revanced_hide_action_button_like_dislike_title">Ocultar botones Me gusta y No me gusta</string>
|
||||||
<string name="revanced_hide_action_button_like_dislike_summary">Oculta los botones \"Me gusta\" y \"no me gusta\". No funciona en el diseño del reproductor antiguo.</string>
|
<string name="revanced_hide_action_button_like_dislike_summary">Oculta los botones \"Me gusta\" y \"no me gusta\". No funciona en el diseño del reproductor antiguo.</string>
|
||||||
<string name="revanced_hide_action_button_comment_title">Ocultar botón de comentarios</string>
|
<string name="revanced_hide_action_button_comment_title">Ocultar botón de comentarios</string>
|
||||||
@ -31,6 +34,9 @@
|
|||||||
<string name="revanced_hide_action_button_radio_summary">Oculta el botón Radio.</string>
|
<string name="revanced_hide_action_button_radio_summary">Oculta el botón Radio.</string>
|
||||||
<string name="revanced_hide_action_button_share_title">Ocultar botón de compartir</string>
|
<string name="revanced_hide_action_button_share_title">Ocultar botón de compartir</string>
|
||||||
<string name="revanced_hide_action_button_share_summary">Oculta el botón Compartir.</string>
|
<string name="revanced_hide_action_button_share_summary">Oculta el botón Compartir.</string>
|
||||||
|
<string name="revanced_hide_action_button_song_video_title">Ocultar el botón de Canción / Video</string>
|
||||||
|
<string name="revanced_hide_action_button_song_video_summary">"Oculta el botón de Canción / Video.
|
||||||
|
(Este botón está disponible para algunos usuarios)"</string>
|
||||||
<string name="revanced_hide_action_button_label_title">Ocultar etiquetas de botón de acción</string>
|
<string name="revanced_hide_action_button_label_title">Ocultar etiquetas de botón de acción</string>
|
||||||
<string name="revanced_hide_action_button_label_summary">Oculta las etiquetas de los botones de acción.</string>
|
<string name="revanced_hide_action_button_label_summary">Oculta las etiquetas de los botones de acción.</string>
|
||||||
<string name="revanced_external_downloader_action_title">Reemplazar botón de acción de Descarga</string>
|
<string name="revanced_external_downloader_action_title">Reemplazar botón de acción de Descarga</string>
|
||||||
@ -48,6 +54,9 @@ Descarga %2$s desde el sitio web."</string>
|
|||||||
<!-- PreferenceScreen: Ads -->
|
<!-- PreferenceScreen: Ads -->
|
||||||
<string name="revanced_preference_screen_ads_title">Anuncios</string>
|
<string name="revanced_preference_screen_ads_title">Anuncios</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_title">Ocultar anuncios en pantalla completa</string>
|
<string name="revanced_hide_fullscreen_ads_title">Ocultar anuncios en pantalla completa</string>
|
||||||
|
<string name="revanced_hide_fullscreen_ads_summary">"Oculta los anuncios en pantalla completa.
|
||||||
|
• Algunas veces puede que se vea una pantalla negra vacía en lugar del inicio."</string>
|
||||||
|
<string name="revanced_fullscreen_ads_closed_toast">Los anuncios en pantalla completa son cerrados.</string>
|
||||||
<string name="revanced_hide_general_ads_title">Ocultar anuncios generales</string>
|
<string name="revanced_hide_general_ads_title">Ocultar anuncios generales</string>
|
||||||
<string name="revanced_hide_general_ads_summary">Oculta anuncios generales.</string>
|
<string name="revanced_hide_general_ads_summary">Oculta anuncios generales.</string>
|
||||||
<string name="revanced_hide_music_ads_title">Ocultar anuncios de música</string>
|
<string name="revanced_hide_music_ads_title">Ocultar anuncios de música</string>
|
||||||
@ -56,6 +65,7 @@ Descarga %2$s desde el sitio web."</string>
|
|||||||
<string name="revanced_hide_paid_promotion_label_summary">Oculta etiqueta de promoción pagada.</string>
|
<string name="revanced_hide_paid_promotion_label_summary">Oculta etiqueta de promoción pagada.</string>
|
||||||
<string name="revanced_hide_premium_promotion_title">Ocultar popups de promoción premium</string>
|
<string name="revanced_hide_premium_promotion_title">Ocultar popups de promoción premium</string>
|
||||||
<string name="revanced_hide_premium_promotion_summary">Oculta popups de promoción premium.</string>
|
<string name="revanced_hide_premium_promotion_summary">Oculta popups de promoción premium.</string>
|
||||||
|
<string name="revanced_hide_premium_promotion_closed_toast">Los mensajes emergentes promocionando premium son cerrados.</string>
|
||||||
<string name="revanced_hide_premium_renewal_title">Ocultar banner de renovación premium</string>
|
<string name="revanced_hide_premium_renewal_title">Ocultar banner de renovación premium</string>
|
||||||
<string name="revanced_hide_premium_renewal_summary">Oculta banner de renovación premium.</string>
|
<string name="revanced_hide_premium_renewal_summary">Oculta banner de renovación premium.</string>
|
||||||
<string name="revanced_hide_promotion_alert_banner_title">Ocultar banner de alerta de promoción</string>
|
<string name="revanced_hide_promotion_alert_banner_title">Ocultar banner de alerta de promoción</string>
|
||||||
@ -87,6 +97,7 @@ Problemas conocidos:
|
|||||||
<string name="revanced_hide_flyout_menu_go_to_episode_title">Ocultar menú de ir a episodios</string>
|
<string name="revanced_hide_flyout_menu_go_to_episode_title">Ocultar menú de ir a episodios</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_podcast_title">Ocultar menú de ir al podcast</string>
|
<string name="revanced_hide_flyout_menu_go_to_podcast_title">Ocultar menú de ir al podcast</string>
|
||||||
<string name="revanced_hide_flyout_menu_help_title">Ocultar menú Ayuda & Comentarios</string>
|
<string name="revanced_hide_flyout_menu_help_title">Ocultar menú Ayuda & Comentarios</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_not_interested_title">Ocultar el menú de \"No interesado\"</string>
|
||||||
<string name="revanced_hide_flyout_menu_pin_to_speed_dial_title">Ocultar el pin al menú de marcación rápida</string>
|
<string name="revanced_hide_flyout_menu_pin_to_speed_dial_title">Ocultar el pin al menú de marcación rápida</string>
|
||||||
<string name="revanced_hide_flyout_menu_play_next_title">Ocultar menú de reproducción siguiente</string>
|
<string name="revanced_hide_flyout_menu_play_next_title">Ocultar menú de reproducción siguiente</string>
|
||||||
<string name="revanced_hide_flyout_menu_quality_title">Ocultar menú de calidad</string>
|
<string name="revanced_hide_flyout_menu_quality_title">Ocultar menú de calidad</string>
|
||||||
@ -182,6 +193,10 @@ Esto no evita la restricción de edad. Solo la acepta automáticamente."</string
|
|||||||
<!-- PreferenceScreen: Navigation bar -->
|
<!-- PreferenceScreen: Navigation bar -->
|
||||||
<string name="revanced_preference_screen_navigation_title">Barra de navegación</string>
|
<string name="revanced_preference_screen_navigation_title">Barra de navegación</string>
|
||||||
<string name="revanced_enable_custom_navigation_bar_color_title">Activar color personalizado de la barra de navegación</string>
|
<string name="revanced_enable_custom_navigation_bar_color_title">Activar color personalizado de la barra de navegación</string>
|
||||||
|
<string name="revanced_enable_custom_navigation_bar_color_summary">Aplica un color en la barra de navegación.</string>
|
||||||
|
<string name="revanced_custom_navigation_bar_color_value_title">Valor de color personalizado para la barra de navegación</string>
|
||||||
|
<string name="revanced_custom_navigation_bar_color_value_summary">Escribe un valor hexadecimal para el color de la barra de navegación.</string>
|
||||||
|
<string name="revanced_custom_navigation_bar_color_value_invalid_invalid_toast">Valor de color hexadecimal Inválido para la barra de navegación.</string>
|
||||||
<string name="revanced_hide_navigation_home_button_title">Ocultar botón de Inicio</string>
|
<string name="revanced_hide_navigation_home_button_title">Ocultar botón de Inicio</string>
|
||||||
<string name="revanced_hide_navigation_home_button_summary">Oculta el botón de Inicio.</string>
|
<string name="revanced_hide_navigation_home_button_summary">Oculta el botón de Inicio.</string>
|
||||||
<string name="revanced_hide_navigation_samples_button_title">Ocultar botón de Samples</string>
|
<string name="revanced_hide_navigation_samples_button_title">Ocultar botón de Samples</string>
|
||||||
@ -198,8 +213,37 @@ Esto no evita la restricción de edad. Solo la acepta automáticamente."</string
|
|||||||
<string name="revanced_hide_navigation_label_summary">Oculta las etiquetas en la barra de navegación.</string>
|
<string name="revanced_hide_navigation_label_summary">Oculta las etiquetas en la barra de navegación.</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Reproductor</string>
|
<string name="revanced_preference_screen_player_title">Reproductor</string>
|
||||||
|
<string name="revanced_add_miniplayer_next_button_title">Añade un botón de siguiente al minireproductor</string>
|
||||||
|
<string name="revanced_add_miniplayer_next_button_summary">Añade un botón de siguiente pista al minireproductor.</string>
|
||||||
|
<string name="revanced_add_miniplayer_previous_button_title">Añade un botón de anterior al minireproductor</string>
|
||||||
|
<string name="revanced_add_miniplayer_previous_button_summary">Añade un botón de pista anterior al minireproductor.</string>
|
||||||
|
<string name="revanced_change_miniplayer_color_title">Cambia el color del minireproductor</string>
|
||||||
|
<string name="revanced_change_miniplayer_color_summary">Cambia el color del minireproductor para que concuerde con el color del reproductor de la pantalla completa.</string>
|
||||||
|
<string name="revanced_change_player_background_color_title">Cambia el color de fondo del reproductor</string>
|
||||||
|
<string name="revanced_change_player_background_color_summary">Cambia el color de fondo del reproductor a un color personalizado.</string>
|
||||||
|
<string name="revanced_custom_player_background_color_primary_title">Color principal del fondo del reproductor</string>
|
||||||
|
<string name="revanced_custom_player_background_color_primary_summary">"Escribe el valor hexadecimal del color primario del fondo del reproductor.
|
||||||
|
|
||||||
|
Preferiblemente que sean colores oscuros, la aplicación no soporta temas claros."</string>
|
||||||
|
<string name="revanced_custom_player_background_color_secondary_title">Color secundario del fondo del reproductor</string>
|
||||||
|
<string name="revanced_custom_player_background_color_secondary_summary">"Escriba el valor hexadecimal del color secundario del reproductor.
|
||||||
|
|
||||||
|
Preferiblemente colores oscuros, la aplicación no soporta temas claros."</string>
|
||||||
|
<string name="revanced_custom_player_background_invalid_toast">Color de fondo del reproductor inválido.</string>
|
||||||
|
<string name="revanced_change_seekbar_position_title">Cambiar posición de la barra de acción</string>
|
||||||
|
<string name="revanced_change_seekbar_position_summary">Mueve la barra de acción por debajo del botón de reproducción.</string>
|
||||||
|
<string name="revanced_disable_miniplayer_gesture_title">Deshabilitar el gesto del minireproductor</string>
|
||||||
|
<string name="revanced_disable_miniplayer_gesture_summary">Deshabilita el gesto de deslizamiento para cambiar de pista en el minireproductor.</string>
|
||||||
<string name="revanced_disable_player_gesture_title">Desactivar gesto del reproductor</string>
|
<string name="revanced_disable_player_gesture_title">Desactivar gesto del reproductor</string>
|
||||||
<string name="revanced_disable_player_gesture_summary">Desactivar el gesto de deslizar para cambiar de pista en el reproductor.</string>
|
<string name="revanced_disable_player_gesture_summary">Desactivar el gesto de deslizar para cambiar de pista en el reproductor.</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_title">Activar el minireproductor forzado</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_summary">Habilita que se fuerce el minireproductor cuando se cambia a una nueva pista.</string>
|
||||||
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">Habilitar el gesto de descarte del minireproductor</string>
|
||||||
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">Habilita que se pueda deslizar hacia abajo en el minireproductor para descartarlo.</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_title">Habilita una barra de acción más gruesa</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_summary">"Habilita una barra de acción más gruesa.
|
||||||
|
|
||||||
|
Limitantes: Los segmentos de SponsorBlock no se mostrarán en la barra de acción."</string>
|
||||||
<string name="revanced_enable_zen_mode_title">Activar modo zen</string>
|
<string name="revanced_enable_zen_mode_title">Activar modo zen</string>
|
||||||
<string name="revanced_enable_zen_mode_summary">Añade un tinte gris al reproductor de vídeo para reducir la fatiga visual.</string>
|
<string name="revanced_enable_zen_mode_summary">Añade un tinte gris al reproductor de vídeo para reducir la fatiga visual.</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_title">Activar el modo Zen en podcasts</string>
|
<string name="revanced_enable_zen_mode_podcast_title">Activar el modo Zen en podcasts</string>
|
||||||
@ -212,6 +256,8 @@ Esto no evita la restricción de edad. Solo la acepta automáticamente."</string
|
|||||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary">Oculta los botones marca de tiempo y emoji al escribir comentarios.</string>
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary">Oculta los botones marca de tiempo y emoji al escribir comentarios.</string>
|
||||||
<string name="revanced_hide_fullscreen_share_button_title">Ocultar el botón Compartir en pantalla completa</string>
|
<string name="revanced_hide_fullscreen_share_button_title">Ocultar el botón Compartir en pantalla completa</string>
|
||||||
<string name="revanced_hide_fullscreen_share_button_summary">Oculta el botón Compartir en el reproductor de pantalla completa.</string>
|
<string name="revanced_hide_fullscreen_share_button_summary">Oculta el botón Compartir en el reproductor de pantalla completa.</string>
|
||||||
|
<string name="revanced_hide_song_video_toggle_title">Ocultar el interruptor de Canción / Video</string>
|
||||||
|
<string name="revanced_hide_song_video_toggle_summary">Oculta el interruptor de Canción / Video en el reproductor.</string>
|
||||||
<string name="revanced_remember_repeat_state_title">Recordar estado de repetición</string>
|
<string name="revanced_remember_repeat_state_title">Recordar estado de repetición</string>
|
||||||
<string name="revanced_remember_repeat_state_summary">Recuerda el estado de la repetición.</string>
|
<string name="revanced_remember_repeat_state_summary">Recuerda el estado de la repetición.</string>
|
||||||
<string name="revanced_remember_shuffle_state_title">Recordar estado aleatorio</string>
|
<string name="revanced_remember_shuffle_state_title">Recordar estado aleatorio</string>
|
||||||
@ -373,11 +419,18 @@ Toca para ver cómo crear una clave de API."</string>
|
|||||||
<string name="revanced_disable_drc_audio_title">Desactivar audio DRC</string>
|
<string name="revanced_disable_drc_audio_title">Desactivar audio DRC</string>
|
||||||
<string name="revanced_disable_drc_audio_summary">Deshabilita DRC (Dynamic Range Compression) aplicado al audio.</string>
|
<string name="revanced_disable_drc_audio_summary">Deshabilita DRC (Dynamic Range Compression) aplicado al audio.</string>
|
||||||
<string name="revanced_disable_music_video_in_album_title">Desactivar vídeo de música en el álbum</string>
|
<string name="revanced_disable_music_video_in_album_title">Desactivar vídeo de música en el álbum</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_summary">"Cuando un usuario no-premium reproduce una canción incluida en un álbum, el video musical a veces es reproducido en lugar de la canción oficial en sí.
|
||||||
|
|
||||||
|
Encuentra y redirige la canción oficial, sí se detecta un video musical al reproducirse desde un álbum.
|
||||||
|
|
||||||
|
Limitantes: Vídeos para niños puede que no se redirijan."</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_title">Tipo de redirección</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_title">Tipo de redirección</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_summary">Especifica cómo redirigir a la canción oficial.</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_summary">Especifica cómo redirigir a la canción oficial.</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">Redirigir</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">Redirigir</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">Interruptor de Audio / Video</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">Interruptor de Audio / Video</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">Mantén pulsado el interruptor de Audio / Video</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">Mantén pulsado el interruptor de Audio / Video</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_title">Desactiva el protocolo QUIC</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_summary">"Deshabilita el protocolo QUIC de CronetEngine."</string>
|
||||||
<string name="revanced_enable_debug_logging_title">Activar registro de depuración</string>
|
<string name="revanced_enable_debug_logging_title">Activar registro de depuración</string>
|
||||||
<string name="revanced_enable_debug_logging_summary">Imprime el registro de depuración.</string>
|
<string name="revanced_enable_debug_logging_summary">Imprime el registro de depuración.</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_title">Incluir búfer en registro de depuración</string>
|
<string name="revanced_enable_debug_buffer_logging_title">Incluir búfer en registro de depuración</string>
|
||||||
@ -387,10 +440,20 @@ Toca para ver cómo crear una clave de API."</string>
|
|||||||
<string name="revanced_sanitize_sharing_links_title">Desinfectar enlaces compartidos</string>
|
<string name="revanced_sanitize_sharing_links_title">Desinfectar enlaces compartidos</string>
|
||||||
<string name="revanced_sanitize_sharing_links_summary">Elimina los parámetros de consulta de seguimiento de las URL al compartir enlaces.</string>
|
<string name="revanced_sanitize_sharing_links_summary">Elimina los parámetros de consulta de seguimiento de las URL al compartir enlaces.</string>
|
||||||
<string name="revanced_spoof_client_title">Falsificar cliente</string>
|
<string name="revanced_spoof_client_title">Falsificar cliente</string>
|
||||||
|
<string name="revanced_spoof_client_summary">Falsifica el cliente para prevenir problemas en la reproducción.</string>
|
||||||
<string name="revanced_spoof_client_type_title">Cliente por defecto</string>
|
<string name="revanced_spoof_client_type_title">Cliente por defecto</string>
|
||||||
|
<string name="revanced_spoof_client_type_summary">Define un cliente de por defecto para el falsificado.</string>
|
||||||
<string name="revanced_spoof_client_type_entry_android_music_4_27">Android Music 4.27.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_4_27">Android Music 4.27.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_watch_history_type_title">Tipo de vista del historial</string>
|
||||||
|
<string name="revanced_watch_history_type_summary">"• Original: Sigue la configuración del registro del historial de su cuenta de Google, pero la opción del registro del historial pueda no funcionar al tener un DNS o VPN.
|
||||||
|
• Reemplazar dominio: Sigue la configuración del registro del historial de su cuenta de Google.
|
||||||
|
• Bloquear el registro del historial: El registro de historial está bloqueado."</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_1">Original</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_2">Reemplazar dominio</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_3">Bloquear el registro del historial</string>
|
||||||
<string name="revanced_default_app_settings_title">Abrir ajustes predeterminados de la app</string>
|
<string name="revanced_default_app_settings_title">Abrir ajustes predeterminados de la app</string>
|
||||||
<string name="revanced_default_app_settings_summary">Para abrir los enlaces de YouTube Music en RVX Music, activa \'Abrir enlaces soportados\' y activa las direcciones web soportadas.</string>
|
<string name="revanced_default_app_settings_summary">Para abrir los enlaces de YouTube Music en RVX Music, activa \'Abrir enlaces soportados\' y activa las direcciones web soportadas.</string>
|
||||||
<string name="gms_core_settings_title">Abrir GmsCore</string>
|
<string name="gms_core_settings_title">Abrir GmsCore</string>
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
<string name="revanced_extended_settings_title">RVX</string>
|
<string name="revanced_extended_settings_title">RVX</string>
|
||||||
<string name="revanced_extended_reset_to_default_toast">Atur ulang ke nilai default.</string>
|
<string name="revanced_extended_reset_to_default_toast">Atur ulang ke nilai default.</string>
|
||||||
<!-- Shared Category -->
|
<!-- Shared Category -->
|
||||||
<string name="revanced_extended_restart_first_run">Mulai ulang untuk memuat layout secara normal</string>
|
<string name="revanced_extended_restart_first_run">Mulai ulang untuk memuat tata letak secara normal</string>
|
||||||
<string name="revanced_extended_restart_message">Refresh dan mulai ulang</string>
|
<string name="revanced_extended_restart_message">Segarkan dan mulai ulang</string>
|
||||||
<!-- PreferenceScreen: Account -->
|
<!-- PreferenceScreen: Account -->
|
||||||
<string name="revanced_preference_screen_account_title">Akun</string>
|
<string name="revanced_preference_screen_account_title">Akun</string>
|
||||||
<string name="revanced_hide_account_menu_title">Sembunyikan menu akun</string>
|
<string name="revanced_hide_account_menu_title">Sembunyikan menu akun</string>
|
||||||
<string name="revanced_hide_account_menu_summary">Menyembunyikan elemen menu akun menggunakan filter custom.</string>
|
<string name="revanced_hide_account_menu_summary">Menyembunyikan elemen menu akun menggunakan penyaring khusus.</string>
|
||||||
<string name="revanced_hide_account_menu_filter_strings_title">Filter menu Akun</string>
|
<string name="revanced_hide_account_menu_filter_strings_title">Penyaring menu Akun</string>
|
||||||
<string name="revanced_hide_account_menu_filter_strings_summary">Daftar dari nama-nama menu akun ke filter, terpisah oleh garis baru.</string>
|
<string name="revanced_hide_account_menu_filter_strings_summary">Daftar nama menu akun yang akan disaring, dipisahkan dengan baris baru.</string>
|
||||||
<string name="revanced_hide_account_menu_empty_component_title">Sembunyikan komponen kosong</string>
|
<string name="revanced_hide_account_menu_empty_component_title">Sembunyikan komponen kosong</string>
|
||||||
<string name="revanced_hide_account_menu_empty_component_summary">Menyembunyikan komponen kosong di menu akun.</string>
|
<string name="revanced_hide_account_menu_empty_component_summary">Menyembunyikan komponen kosong di menu akun.</string>
|
||||||
<string name="revanced_hide_handle_title">Sembunyikan handle</string>
|
<string name="revanced_hide_handle_title">Sembunyikan handle</string>
|
||||||
@ -20,13 +20,13 @@
|
|||||||
<string name="revanced_hide_terms_container_summary">Menyembunyikan kontainer ketentuan layanan.</string>
|
<string name="revanced_hide_terms_container_summary">Menyembunyikan kontainer ketentuan layanan.</string>
|
||||||
<!-- PreferenceScreen: Action bar -->
|
<!-- PreferenceScreen: Action bar -->
|
||||||
<string name="revanced_preference_screen_action_bar_title">Bilah Tindakan</string>
|
<string name="revanced_preference_screen_action_bar_title">Bilah Tindakan</string>
|
||||||
<string name="revanced_change_action_bar_position_title">Ubah posisi bilah aksi</string>
|
<string name="revanced_change_action_bar_position_title">Ubah posisi bilah tindakan</string>
|
||||||
<string name="revanced_change_action_bar_position_summary">Pindahkan bilah aksi di bawah tombol putar.</string>
|
<string name="revanced_change_action_bar_position_summary">Pindahkan bilah tindakan di bawah tombol putar.</string>
|
||||||
<string name="revanced_hide_action_button_like_dislike_title">Sembunyikan tombol Like dan Dislike</string>
|
<string name="revanced_hide_action_button_like_dislike_title">Sembunyikan tombol Suka dan Tidak suka</string>
|
||||||
<string name="revanced_hide_action_button_like_dislike_summary">Menyembunyikan tombol Like dan Dislike. Itu tidak akan bekerja di layout player lama.</string>
|
<string name="revanced_hide_action_button_like_dislike_summary">Menyembunyikan tombol Suka dan Tidak suka. Itu tidak akan bekerja di tata letak pemutar lama.</string>
|
||||||
<string name="revanced_hide_action_button_comment_title">Sembunyikan tombol Komentar</string>
|
<string name="revanced_hide_action_button_comment_title">Sembunyikan tombol Komentar</string>
|
||||||
<string name="revanced_hide_action_button_comment_summary">Menyembunyikan tombol Komentar.</string>
|
<string name="revanced_hide_action_button_comment_summary">Menyembunyikan tombol Komentar.</string>
|
||||||
<string name="revanced_hide_action_button_add_to_playlist_title">Sembunyikan tombol Save</string>
|
<string name="revanced_hide_action_button_add_to_playlist_title">Sembunyikan tombol Simpan</string>
|
||||||
<string name="revanced_hide_action_button_add_to_playlist_summary">Menyembunyikan tombol Simpan.</string>
|
<string name="revanced_hide_action_button_add_to_playlist_summary">Menyembunyikan tombol Simpan.</string>
|
||||||
<string name="revanced_hide_action_button_download_title">Sembunyikan tombol Unduh</string>
|
<string name="revanced_hide_action_button_download_title">Sembunyikan tombol Unduh</string>
|
||||||
<string name="revanced_hide_action_button_download_summary">Menyembunyikan tombol Unduh.</string>
|
<string name="revanced_hide_action_button_download_summary">Menyembunyikan tombol Unduh.</string>
|
||||||
@ -37,27 +37,31 @@
|
|||||||
<string name="revanced_hide_action_button_song_video_title">Sembunyikan tombol Lagu / Video</string>
|
<string name="revanced_hide_action_button_song_video_title">Sembunyikan tombol Lagu / Video</string>
|
||||||
<string name="revanced_hide_action_button_song_video_summary">"Sembunyikan tombol Lagu / Video.
|
<string name="revanced_hide_action_button_song_video_summary">"Sembunyikan tombol Lagu / Video.
|
||||||
(Tombol ini hanya tersedia untuk sebagian pengguna)"</string>
|
(Tombol ini hanya tersedia untuk sebagian pengguna)"</string>
|
||||||
<string name="revanced_hide_action_button_label_title">Sembunyikan tombol bilah tindakan</string>
|
<string name="revanced_hide_action_button_label_title">Sembunyikan label tombol tindakan</string>
|
||||||
<string name="revanced_hide_action_button_label_summary">Menyembunyikan bilah dari tombol tindakan.</string>
|
<string name="revanced_hide_action_button_label_summary">Menyembunyikan label tombol tindakan.</string>
|
||||||
<string name="revanced_external_downloader_action_title">Ganti tombol tindakan Unduh</string>
|
<string name="revanced_external_downloader_action_title">Ganti tombol tindakan Unduh</string>
|
||||||
<string name="revanced_external_downloader_action_summary">"Tombol Unduh membuka Downloader eksternal kamu.
|
<string name="revanced_external_downloader_action_summary">"Tombol Unduh membuka pengunduh eksternal Anda
|
||||||
|
|
||||||
• Hanya menggantikan tombol Unduh di player.
|
• Hanya mengganti tombol tindakan Unduh di pemutar.
|
||||||
• Tidak bisa menggantikan tombol Unduh di menu flyout atau tab Library."</string>
|
• Tidak mengganti tombol Unduh di menu flyout atau tab Pustaka."</string>
|
||||||
<string name="revanced_external_downloader_package_name_title">Nama paket downloader eksternal</string>
|
<string name="revanced_external_downloader_package_name_title">Nama paket pengunduh eksternal</string>
|
||||||
<string name="revanced_external_downloader_package_name_summary">Nama paket aplikasi downloader eksternal yang terinstal, seperti NewPipe atau YTDLnis.</string>
|
<string name="revanced_external_downloader_package_name_summary">Nama paket aplikasi pengunduh eksternal yang terpasang, seperti NewPipe atau YTDLnis.</string>
|
||||||
<string name="revanced_external_downloader_dialog_title">Downloader eksternal</string>
|
<string name="revanced_external_downloader_dialog_title">Pengunduh eksternal</string>
|
||||||
<string name="revanced_external_downloader_not_installed_dialog_title">Peringatan</string>
|
<string name="revanced_external_downloader_not_installed_dialog_title">Peringatan</string>
|
||||||
<string name="revanced_external_downloader_not_installed_dialog_message">"%1$s belum terinstall.
|
<string name="revanced_external_downloader_not_installed_dialog_message">"%1$s belum terpasang.
|
||||||
Download %2$s dari website."</string>
|
Harap unduh %2$s dari website."</string>
|
||||||
<string name="revanced_external_downloader_not_installed_warning">%s tidak diinstal. Silakan instal.</string>
|
<string name="revanced_external_downloader_not_installed_warning">%s tidak dipasang. Silakan pasang terlebih dahulu.</string>
|
||||||
<!-- PreferenceScreen: Ads -->
|
<!-- PreferenceScreen: Ads -->
|
||||||
<string name="revanced_preference_screen_ads_title">Iklan</string>
|
<string name="revanced_preference_screen_ads_title">Iklan</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_title">Sembunyikan iklan fullscreen</string>
|
<string name="revanced_hide_fullscreen_ads_title">Sembunyikan iklan layar penuh</string>
|
||||||
|
<string name="revanced_hide_fullscreen_ads_summary">"Menyembunyikan iklan layar penuh.
|
||||||
|
|
||||||
|
Keterbatasan:
|
||||||
|
• Terkadang Anda mungkin melihat layar hitam kosong, bukan feed beranda."</string>
|
||||||
<string name="revanced_fullscreen_ads_closed_toast">Iklan layar penuh ditutup.</string>
|
<string name="revanced_fullscreen_ads_closed_toast">Iklan layar penuh ditutup.</string>
|
||||||
<string name="revanced_hide_general_ads_title">Sembunyikan Iklan Umum</string>
|
<string name="revanced_hide_general_ads_title">Sembunyikan Iklan Umum</string>
|
||||||
<string name="revanced_hide_general_ads_summary">Menyembunyikan Iklan Umum.</string>
|
<string name="revanced_hide_general_ads_summary">Menyembunyikan Iklan Umum.</string>
|
||||||
<string name="revanced_hide_music_ads_title">Sembunyikan iklan musik</string>
|
<string name="revanced_hide_music_ads_title">Sembunyikan iklan media</string>
|
||||||
<string name="revanced_hide_music_ads_summary">Menyembunyikan iklan sebelum memutar musik.</string>
|
<string name="revanced_hide_music_ads_summary">Menyembunyikan iklan sebelum memutar musik.</string>
|
||||||
<string name="revanced_hide_paid_promotion_label_title">Sembunyikan label promosi berbayar</string>
|
<string name="revanced_hide_paid_promotion_label_title">Sembunyikan label promosi berbayar</string>
|
||||||
<string name="revanced_hide_paid_promotion_label_summary">Menyembunyikan label promosi berbayar.</string>
|
<string name="revanced_hide_paid_promotion_label_summary">Menyembunyikan label promosi berbayar.</string>
|
||||||
@ -67,289 +71,411 @@ Download %2$s dari website."</string>
|
|||||||
<string name="revanced_hide_premium_renewal_title">Sembunyikan banner pembaruan premium</string>
|
<string name="revanced_hide_premium_renewal_title">Sembunyikan banner pembaruan premium</string>
|
||||||
<string name="revanced_hide_premium_renewal_summary">Menyembunyikan banner pembaruan premium.</string>
|
<string name="revanced_hide_premium_renewal_summary">Menyembunyikan banner pembaruan premium.</string>
|
||||||
<string name="revanced_hide_promotion_alert_banner_title">Sembunyikan banner peringatan promosi</string>
|
<string name="revanced_hide_promotion_alert_banner_title">Sembunyikan banner peringatan promosi</string>
|
||||||
|
<string name="revanced_hide_promotion_alert_banner_summary">Sembunyikan banner peringatan promosi.</string>
|
||||||
<!-- PreferenceScreen: Flyout menu -->
|
<!-- PreferenceScreen: Flyout menu -->
|
||||||
<string name="revanced_preference_screen_flyout_title">Menu flyout</string>
|
<string name="revanced_preference_screen_flyout_title">Menu flyout</string>
|
||||||
<string name="revanced_enable_trim_silence_title">Tambah switch Trim silence</string>
|
<string name="revanced_enable_trim_silence_title">Tambah tombol Pangkas keheningan</string>
|
||||||
<string name="revanced_enable_trim_silence_summary">"Menambahkan tombol Trim silence ke menu flyout playback speed.
|
<string name="revanced_enable_trim_silence_summary">"Menambahkan tombol Pangkas keheningan ke menu flyout kecepatan pemutaran.
|
||||||
|
|
||||||
Info:
|
Info:
|
||||||
• Fitur ini hanya untuk podcast.
|
• Fitur ini hanya untuk podcast.
|
||||||
• Fitur ini masih dalam pengembangan, jadi ini tidak akan stabil."</string>
|
• Fitur ini masih dalam pengembangan, jadi mungkin tidak stabil."</string>
|
||||||
<string name="revanced_enable_compact_dialog_title">Aktifkan dialog ringkas</string>
|
<string name="revanced_enable_compact_dialog_title">Aktifkan dialog ringkas</string>
|
||||||
<string name="revanced_enable_compact_dialog_summary">"Aktifkan dialog ringkas di ponsel.
|
<string name="revanced_enable_compact_dialog_summary">"Mengaktifkan dialog ringkas di ponsel.
|
||||||
|
|
||||||
Masalah yang diketahui:
|
Keterbatasan:
|
||||||
• Gambar album di Tab library juga menjadi lebih kecil.
|
• Gambar album di tab Pustaka juga menjadi lebih kecil ketika diatur dalam model kotak.
|
||||||
• Tata letak pengatur waktu tidur mungkin terlihat tidak biasa."</string>
|
• Tata letak pengatur waktu tidur mungkin terlihat tidak biasa."</string>
|
||||||
<string name="revanced_hide_flyout_menu_like_dislike_title">Sembunyikan tombol Like dan Dislike</string>
|
<string name="revanced_hide_flyout_menu_like_dislike_title">Sembunyikan tombol Suka dan Tidak suka</string>
|
||||||
<string name="revanced_hide_flyout_menu_3_column_component_title">Sembunyikan komponen 3-kolom</string>
|
<string name="revanced_hide_flyout_menu_3_column_component_title">Sembunyikan komponen 3-kolom</string>
|
||||||
<string name="revanced_hide_flyout_menu_add_to_queue_title">Sembunyikan menu tambahkan ke antrean</string>
|
<string name="revanced_hide_flyout_menu_add_to_queue_title">Sembunyikan menu tambahkan ke antrean</string>
|
||||||
<string name="revanced_hide_flyout_menu_captions_title">Sembunyikan menu teks</string>
|
<string name="revanced_hide_flyout_menu_captions_title">Sembunyikan menu Teks</string>
|
||||||
<string name="revanced_hide_flyout_menu_delete_playlist_title">Sembunyikan menu hapus playlist</string>
|
<string name="revanced_hide_flyout_menu_delete_playlist_title">Sembunyikan menu Hapus playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_dismiss_queue_title">Sembunyikan menu abaikan antrean</string>
|
<string name="revanced_hide_flyout_menu_dismiss_queue_title">Sembunyikan menu Abaikan antrean</string>
|
||||||
<string name="revanced_hide_flyout_menu_download_title">Sembunyikan menu Unduh</string>
|
<string name="revanced_hide_flyout_menu_download_title">Sembunyikan menu Unduh</string>
|
||||||
<string name="revanced_hide_flyout_menu_edit_playlist_title">Sembunyikan menu edit playlist</string>
|
<string name="revanced_hide_flyout_menu_edit_playlist_title">Sembunyikan menu Edit playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_album_title">Sembunyikan menu Pergi ke album</string>
|
<string name="revanced_hide_flyout_menu_go_to_album_title">Sembunyikan menu Pergi ke album</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_artist_title">Sembunyikan menu Pergi ke artis</string>
|
<string name="revanced_hide_flyout_menu_go_to_artist_title">Sembunyikan menu Pergi ke artis</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_episode_title">Sembunyikan menu Pergi ke episode</string>
|
<string name="revanced_hide_flyout_menu_go_to_episode_title">Sembunyikan menu Pergi ke episode</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_podcast_title">Sembunyikan menu Pergi ke podcast</string>
|
<string name="revanced_hide_flyout_menu_go_to_podcast_title">Sembunyikan menu Pergi ke podcast</string>
|
||||||
<string name="revanced_hide_flyout_menu_help_title">Sembunyikan menu bantuan & saran</string>
|
<string name="revanced_hide_flyout_menu_help_title">Sembunyikan menu Bantuan & saran</string>
|
||||||
<string name="revanced_hide_flyout_menu_play_next_title">Sembunyikan menu putar berikutnya</string>
|
<string name="revanced_hide_flyout_menu_not_interested_title">Sembunyikan menu Tidak tertarik</string>
|
||||||
<string name="revanced_hide_flyout_menu_quality_title">Hide menu Kualitas</string>
|
<string name="revanced_hide_flyout_menu_pin_to_speed_dial_title">Sembunyikan Pin ke menu Panggil cepat</string>
|
||||||
<string name="revanced_hide_flyout_menu_remove_from_library_title">Sembunyikan menu hapus dari koleksi</string>
|
<string name="revanced_hide_flyout_menu_play_next_title">Sembunyikan menu Putar berikutnya</string>
|
||||||
<string name="revanced_hide_flyout_menu_remove_from_playlist_title">Sembunyikan hapus dari menu playlist</string>
|
<string name="revanced_hide_flyout_menu_quality_title">Sembunyikan menu Kualitas</string>
|
||||||
<string name="revanced_hide_flyout_menu_report_title">Sembunyikan menu laporkan</string>
|
<string name="revanced_hide_flyout_menu_remove_from_library_title">Sembunyikan menu Hapus dari koleksi</string>
|
||||||
<string name="revanced_hide_flyout_menu_save_episode_for_later_title">Sembunyikan menu simpan episode untuk ditonton nanti</string>
|
<string name="revanced_hide_flyout_menu_remove_from_playlist_title">Sembunyikan menu Hapus dari playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_save_to_library_title">Sembunyikan menu simpan ke koleksi</string>
|
<string name="revanced_hide_flyout_menu_report_title">Sembunyikan menu Laporkan</string>
|
||||||
<string name="revanced_hide_flyout_menu_save_to_playlist_title">Sembunyikan menu simpan ke playlist</string>
|
<string name="revanced_hide_flyout_menu_save_episode_for_later_title">Sembunyikan menu Simpan episode untuk nanti</string>
|
||||||
<string name="revanced_hide_flyout_menu_share_title">Sembunyikan menu bagikan</string>
|
<string name="revanced_hide_flyout_menu_save_to_library_title">Sembunyikan menu Simpan ke pustaka</string>
|
||||||
<string name="revanced_hide_flyout_menu_shuffle_play_title">Sembunyikan menu putar acak</string>
|
<string name="revanced_hide_flyout_menu_save_to_playlist_title">Sembunyikan menu Simpan ke playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_sleep_timer_title">Sembunyikan menu waktu tidur</string>
|
<string name="revanced_hide_flyout_menu_share_title">Sembunyikan menu Bagikan</string>
|
||||||
<string name="revanced_hide_flyout_menu_start_radio_title">Sembunyikan menu mulai radio</string>
|
<string name="revanced_hide_flyout_menu_shuffle_play_title">Sembunyikan menu Putar acak</string>
|
||||||
<string name="revanced_hide_flyout_menu_stats_for_nerds_title">Sembunyikan menu statistik untuk nerds</string>
|
<string name="revanced_hide_flyout_menu_sleep_timer_title">Sembunyikan menu Waktu tidur</string>
|
||||||
<string name="revanced_hide_flyout_menu_subscribe_title">Sembunyikan menu Subscribe / Unsubscribe</string>
|
<string name="revanced_hide_flyout_menu_start_radio_title">Sembunyikan menu Mulai radio</string>
|
||||||
<string name="revanced_hide_flyout_menu_view_song_credit_title">Sembunyikan menu kredit lagu</string>
|
<string name="revanced_hide_flyout_menu_stats_for_nerds_title">Sembunyikan menu Statistik untuk nerds</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_subscribe_title">Sembunyikan menu Berlangganan / Berhenti Berlangganan</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_unpin_from_speed_dial_title">Sembunyikan Buka pin dari menu panggilan cepat</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_view_song_credit_title">Sembunyikan menu Lihat kredit lagu</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_title">Lanjutkan menonton</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_title">Lanjutkan menonton</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_summary">Melanjutkan video dari waktu saat ini ketika berlaih ke YouTube.</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_summary">Melanjutkan video dari waktu saat ini ketika beralih ke YouTube.</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_label">Tonton di YouTube</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_label">Tonton di YouTube</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_warning">Url video tidak valid.</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_warning">Url video tidak sah.</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_title">Ganti menu hapus antrean</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_title">Ganti menu Hapus antrean</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_summary">Menggantikan menu hapus antrean menjadi tonton di YouTube.</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_summary">Menggantikan menu Hapus antrean dengan menu Tonton di YouTube.</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_title">Ganti menu laporkan</string>
|
<string name="revanced_replace_flyout_menu_report_title">Ganti menu Laporkan</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_summary">Menggantikan menu laporkan dengan menu Kecepatan pemutaran.</string>
|
<string name="revanced_replace_flyout_menu_report_summary">Menggantikan menu Laporkan dengan menu Kecepatan pemutaran.</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_only_player_title">Simpan laporkan di komentar</string>
|
<string name="revanced_replace_flyout_menu_report_only_player_title">Simpan Laporkan di komentar</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_only_player_summary">Mempertahankan menu laporkan di bagian komentar.</string>
|
<string name="revanced_replace_flyout_menu_report_only_player_summary">Menyimpan menu Laporkan di bagian komentar tetap utuh.</string>
|
||||||
<!-- PreferenceScreen: General -->
|
<!-- PreferenceScreen: General -->
|
||||||
<string name="revanced_preference_screen_general_title">Umum</string>
|
<string name="revanced_preference_screen_general_title">Umum</string>
|
||||||
<string name="revanced_change_start_page_title">Ganti Halaman Awal</string>
|
<string name="revanced_change_start_page_title">Ganti Halaman Awal</string>
|
||||||
<string name="revanced_change_start_page_summary">Select which page the app opens in.</string>
|
<string name="revanced_change_start_page_summary">Pilih di halaman mana aplikasi dibuka.</string>
|
||||||
|
<string name="revanced_change_start_page_entry_default">Bawaan</string>
|
||||||
|
<string name="revanced_change_start_page_entry_charts">Tangga lagu</string>
|
||||||
|
<string name="revanced_change_start_page_entry_episodes_for_later">Episode untuk Nanti</string>
|
||||||
<string name="revanced_change_start_page_entry_explore">Jelajahi</string>
|
<string name="revanced_change_start_page_entry_explore">Jelajahi</string>
|
||||||
<string name="revanced_change_start_page_entry_library">Koleksi</string>
|
<string name="revanced_change_start_page_entry_history">Riwayat</string>
|
||||||
<string name="revanced_disable_dislike_redirection_title">Disable dislike redirection</string>
|
<string name="revanced_change_start_page_entry_library">Pustaka</string>
|
||||||
<string name="revanced_disable_dislike_redirection_summary">Disables redirection to the next track when clicking the Dislike button.</string>
|
<string name="revanced_change_start_page_entry_liked_music">Musik yang Disukai</string>
|
||||||
|
<string name="revanced_change_start_page_entry_podcasts">Podcast</string>
|
||||||
|
<string name="revanced_change_start_page_entry_samples">Sampel</string>
|
||||||
|
<string name="revanced_change_start_page_entry_search">Cari</string>
|
||||||
|
<string name="revanced_change_start_page_entry_subscriptions">Berlangganan</string>
|
||||||
|
<string name="revanced_disable_dislike_redirection_title">Nonaktifkan pengalihan tidak suka</string>
|
||||||
|
<string name="revanced_disable_dislike_redirection_summary">Menonaktifkan pengalihan ke trek berikutnya ketika mengklik tombol Tidak Suka.</string>
|
||||||
<string name="revanced_disable_auto_captions_title">Nonaktifkan teks otomatis paksa</string>
|
<string name="revanced_disable_auto_captions_title">Nonaktifkan teks otomatis paksa</string>
|
||||||
<string name="revanced_disable_auto_captions_summary">Teks otomatis paksa yang dinonaktifkan.</string>
|
<string name="revanced_disable_auto_captions_summary">Menonaktifkan teks otomatis agar tidak aktif.</string>
|
||||||
<string name="revanced_enable_landscape_mode_title">Aktifkan mode lanskap</string>
|
<string name="revanced_enable_landscape_mode_title">Aktifkan mode lanskap</string>
|
||||||
<string name="revanced_enable_landscape_mode_summary">Mengaktifkan masuk ke mode lanskap dengan rotasi layar di ponsel.</string>
|
<string name="revanced_enable_landscape_mode_summary">Mengaktifkan mode lanskap saat memutar layar ponsel.</string>
|
||||||
<string name="revanced_custom_filter_title">Aktifkan filter kustom</string>
|
<string name="revanced_custom_filter_title">Aktifkan filter khusus</string>
|
||||||
<string name="revanced_custom_filter_summary">Mengaktifkan filter kustom untuk menyembunyikan komponen tata letak.</string>
|
<string name="revanced_custom_filter_summary">Mengaktifkan filter kustom untuk menyembunyikan komponen tata letak.</string>
|
||||||
<string name="revanced_custom_filter_strings_title">Edit filter kustom</string>
|
<string name="revanced_custom_filter_strings_title">Edit filter khusus</string>
|
||||||
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
|
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
|
||||||
<string name="revanced_custom_filter_strings_summary">Memfilter nama komponen dengan baris yang dipisahkan.</string>
|
<string name="revanced_custom_filter_strings_summary">Daftar string pembangun jalur komponen yang akan disaring, dipisahkan dengan baris baru.</string>
|
||||||
<string name="revanced_custom_filter_toast_invalid_syntax">Invalid custom filter: %s.</string>
|
<string name="revanced_custom_filter_toast_invalid_syntax">Filter khusus tidak sah: %s.</string>
|
||||||
<string name="revanced_hide_button_shelf_title">Sembunyikan rak tombol</string>
|
<string name="revanced_hide_button_shelf_title">Sembunyikan rak tombol</string>
|
||||||
<string name="revanced_hide_button_shelf_summary">Menyembunyikan rak tombol dari beranda dan eksplorasi.</string>
|
<string name="revanced_hide_button_shelf_summary">Menyembunyikan rak tombol di feed.</string>
|
||||||
<string name="revanced_hide_carousel_shelf_title">Sembunyikan rak korsel</string>
|
<string name="revanced_hide_carousel_shelf_title">Menyembunyikan rak carousel</string>
|
||||||
<string name="revanced_hide_carousel_shelf_summary">Menyembunyikan rak korsel dari beranda dan eksplorasi.</string>
|
<string name="revanced_hide_carousel_shelf_summary">Menyembunyikan rak carousel di feed.</string>
|
||||||
<string name="revanced_hide_cast_button_title">Sembunyikan tombol cast</string>
|
<string name="revanced_hide_cast_button_title">Sembunyikan tombol Cast</string>
|
||||||
<string name="revanced_hide_cast_button_summary">Menyembunyikan tombol cast.</string>
|
<string name="revanced_hide_cast_button_summary">Menyembunyikan tombol Cast.</string>
|
||||||
<string name="revanced_hide_category_bar_title">Sembunyikan bilah kategori</string>
|
<string name="revanced_hide_category_bar_title">Sembunyikan bilah kategori</string>
|
||||||
<string name="revanced_hide_category_bar_summary">Menyembunyikan bilah kategori musik di bagian atas beranda.</string>
|
<string name="revanced_hide_category_bar_summary">Menyembunyikan bilah kategori.</string>
|
||||||
<string name="revanced_hide_floating_button_title">Hide floating button</string>
|
<string name="revanced_hide_floating_button_title">Sembunyikan tombol mengambang</string>
|
||||||
<string name="revanced_hide_floating_button_summary">Hides the floating button in the Library tab.</string>
|
<string name="revanced_hide_floating_button_summary">Menyembunyikan tombol mengambang di tab Pustaka.</string>
|
||||||
<string name="revanced_hide_history_button_title">Sembunyikan tombol riwayat</string>
|
<string name="revanced_hide_history_button_title">Sembunyikan tombol Riwayat</string>
|
||||||
<string name="revanced_hide_history_button_summary">Menyembunyikan tombol riwayat di toolbar.</string>
|
<string name="revanced_hide_history_button_summary">Menyembunyikan Rombol riwayat di toolbar.</string>
|
||||||
<string name="revanced_hide_notification_button_title">Hide Notifications button</string>
|
<string name="revanced_hide_notification_button_title">Sembunyikan tombol Pemberitahuan</string>
|
||||||
<string name="revanced_hide_notification_button_summary">Hides the Notifications button in the toolbar.</string>
|
<string name="revanced_hide_notification_button_summary">Menyembunyikan tombol Pemberitahuan di toolbar.</string>
|
||||||
<string name="revanced_hide_playlist_card_shelf_title">Hide playlist card shelf</string>
|
<string name="revanced_hide_playlist_card_shelf_title">Sembunyikan rak kartu playlist</string>
|
||||||
<string name="revanced_hide_playlist_card_shelf_summary">Hides the playlist card shelf in the feed.</string>
|
<string name="revanced_hide_playlist_card_shelf_summary">Menyembunyikan rak kartu playlist di feed.</string>
|
||||||
<string name="revanced_hide_samples_shelf_title">Hide Samples shelf</string>
|
<string name="revanced_hide_samples_shelf_title">Sembunyikan rak Sampel</string>
|
||||||
<string name="revanced_hide_samples_shelf_summary">Hides the Samples shelf in the feed.</string>
|
<string name="revanced_hide_samples_shelf_summary">Menyembunyikan rak Sampel di feed.</string>
|
||||||
<string name="revanced_hide_sound_search_button_title">Hide sound search button</string>
|
<string name="revanced_hide_sound_search_button_title">Sembunyikan tombol pencarian suara</string>
|
||||||
<string name="revanced_hide_sound_search_button_summary">Hides the sound search button in the search bar.</string>
|
<string name="revanced_hide_sound_search_button_summary">Menyembunyikan tombol pencarian suara di bilah pencarian.</string>
|
||||||
<string name="revanced_hide_tap_to_update_button_title">Hide \'Tap to update\' button</string>
|
<string name="revanced_hide_tap_to_update_button_title">Sembunyikan tombol Ketuk untuk memperbarui</string>
|
||||||
<string name="revanced_hide_tap_to_update_button_summary">Hides the \'Tap to update\' button.</string>
|
<string name="revanced_hide_tap_to_update_button_summary">Menyembunyikan tombol Ketuk untuk memperbarui.</string>
|
||||||
<string name="revanced_hide_voice_search_button_title">Hide voice search button</string>
|
<string name="revanced_hide_voice_search_button_title">Sembunyikan tombol pencarian suara</string>
|
||||||
<string name="revanced_hide_voice_search_button_summary">Hides the voice search button in the search bar.</string>
|
<string name="revanced_hide_voice_search_button_summary">Menyembunyikan tombol pencarian suara di bilah pencarian.</string>
|
||||||
<string name="revanced_restore_old_style_library_shelf_title">Restore old style library shelf</string>
|
<string name="revanced_restore_old_style_library_shelf_title">Pulihkan tab Pustaka lama</string>
|
||||||
<string name="revanced_restore_old_style_library_shelf_summary">Returns the Library tab to the old style. (Experimental)</string>
|
<string name="revanced_restore_old_style_library_shelf_summary">Memulihkan tab Pustaka ke gaya lama. (Eksperimental)</string>
|
||||||
<string name="revanced_remove_viewer_discretion_dialog_title">Remove viewer discretion dialog</string>
|
<string name="revanced_remove_viewer_discretion_dialog_title">Hapus dialog pembatasan penonton</string>
|
||||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"Removes the viewer discretion dialog.
|
<string name="revanced_remove_viewer_discretion_dialog_summary">"Menghapus dialog pembatasan penonton.
|
||||||
This does not bypass the age restriction. It just accepts it automatically."</string>
|
Ini tidak mengabaikan pembatasan usia. Ini hanya menerimanya secara otomatis."</string>
|
||||||
<string name="revanced_spoof_app_version_title">Palsukan versi aplikasi</string>
|
<string name="revanced_spoof_app_version_title">Palsukan versi aplikasi</string>
|
||||||
<string name="revanced_spoof_app_version_summary">"Memalsukan versi klien ke versi lama
|
<string name="revanced_spoof_app_version_summary">"Memalsukan versi klien ke versi lama.
|
||||||
|
|
||||||
• Ini akan mengubah tampilan aplikasi, namun efek samping yang tidak diketahui mungkin terjadi.
|
• Ini akan mengubah tampilan aplikasi, namun efek samping yang tidak diketahui mungkin terjadi.
|
||||||
• Jika nanti dinonaktifkan, UI lama mungkin tetap ada hingga aplikasi dihapus data."</string>
|
• Jika nanti dinonaktifkan, UI lama mungkin tetap ada hingga data aplikasi dihapus."</string>
|
||||||
<string name="revanced_spoof_app_version_target_title">Target pemalsuan versi aplikasi</string>
|
<string name="revanced_spoof_app_version_target_title">Target pemalsuan versi aplikasi</string>
|
||||||
<string name="revanced_spoof_app_version_target_summary">Pilih target pemalsuan versi aplikasi.</string>
|
<string name="revanced_spoof_app_version_target_summary">Pilih target pemalsuan versi aplikasi.</string>
|
||||||
<string name="revanced_spoof_app_version_target_entry_6_42_55"></string>
|
<string name="revanced_spoof_app_version_target_entry_6_42_55">6.42.55 - Nonaktifkan lirik real-time</string>
|
||||||
|
<string name="revanced_spoof_app_version_target_entry_7_16_53">7.16.53 - Pulihkan bilah tindakan lama</string>
|
||||||
<!-- PreferenceScreen: Navigation bar -->
|
<!-- PreferenceScreen: Navigation bar -->
|
||||||
<string name="revanced_preference_screen_navigation_title">Bilah Navigasi</string>
|
<string name="revanced_preference_screen_navigation_title">Bilah Navigasi</string>
|
||||||
<string name="revanced_hide_navigation_home_button_title">Hide Home button</string>
|
<string name="revanced_enable_custom_navigation_bar_color_title">Aktifkan warna bilah navigasi khusus</string>
|
||||||
<string name="revanced_hide_navigation_home_button_summary">Hides the Home button.</string>
|
<string name="revanced_enable_custom_navigation_bar_color_summary">Atur warna bilah navigasi.</string>
|
||||||
<string name="revanced_hide_navigation_samples_button_title">Hide Samples button</string>
|
<string name="revanced_custom_navigation_bar_color_value_title">Nilai warna bilah navigasi khusus</string>
|
||||||
<string name="revanced_hide_navigation_samples_button_summary">Hides the Samples button.</string>
|
<string name="revanced_custom_navigation_bar_color_value_summary">Masukkan kode hex dari warna bilah navigasi.</string>
|
||||||
<string name="revanced_hide_navigation_explore_button_title">Hide Explore button</string>
|
<string name="revanced_custom_navigation_bar_color_value_invalid_invalid_toast">Nilai warna bilah navigasi tidak sah.</string>
|
||||||
<string name="revanced_hide_navigation_explore_button_summary">Hides the Explore button.</string>
|
<string name="revanced_hide_navigation_home_button_title">Sembunyikan tombol Beranda</string>
|
||||||
<string name="revanced_hide_navigation_library_button_title">Hide Library button</string>
|
<string name="revanced_hide_navigation_home_button_summary">Menyembunyikan tombol Beranda.</string>
|
||||||
<string name="revanced_hide_navigation_library_button_summary">Hides the Library button.</string>
|
<string name="revanced_hide_navigation_samples_button_title">Sembunyikan tombol Sampel</string>
|
||||||
<string name="revanced_hide_navigation_upgrade_button_title">Hide Upgrade button</string>
|
<string name="revanced_hide_navigation_samples_button_summary">Menyembunyikan tombol Sampel.</string>
|
||||||
<string name="revanced_hide_navigation_upgrade_button_summary">Hides the Upgrade button.</string>
|
<string name="revanced_hide_navigation_explore_button_title">Sembunyikan tombol Jelajahi</string>
|
||||||
<string name="revanced_hide_navigation_bar_title">Menyembunyikan bilah navigasi</string>
|
<string name="revanced_hide_navigation_explore_button_summary">Menyembunyikan tombol Jelajahi.</string>
|
||||||
<string name="revanced_hide_navigation_bar_summary">Sembunyikan bilah navigasi.</string>
|
<string name="revanced_hide_navigation_library_button_title">Sembunyikan tombol Pustaka</string>
|
||||||
|
<string name="revanced_hide_navigation_library_button_summary">Menyembunyikan tombol Pustaka.</string>
|
||||||
|
<string name="revanced_hide_navigation_upgrade_button_title">Sembunyikan tombol Upgrade</string>
|
||||||
|
<string name="revanced_hide_navigation_upgrade_button_summary">Menyembunyikan tombol Upgrade.</string>
|
||||||
|
<string name="revanced_hide_navigation_bar_title">Sembunyikan bilah navigasi</string>
|
||||||
|
<string name="revanced_hide_navigation_bar_summary">Menyembunyikan bilah navigasi.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Sembunyikan label navigasi</string>
|
<string name="revanced_hide_navigation_label_title">Sembunyikan label navigasi</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Menyembunyikan label di bilah navigasi.</string>
|
<string name="revanced_hide_navigation_label_summary">Menyembunyikan label di bawah setiap tombol navigasi.</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Player</string>
|
<string name="revanced_preference_screen_player_title">Pemutar</string>
|
||||||
<string name="revanced_disable_player_gesture_title">Menonaktifkan gerakan pemutar</string>
|
<string name="revanced_add_miniplayer_next_button_title">Menambahkan tombol berikutnya pemutar mini</string>
|
||||||
<string name="revanced_disable_player_gesture_summary">Nonaktifkan usap untuk mengubah trek di pemutar.</string>
|
<string name="revanced_add_miniplayer_next_button_summary">Menambahkan tombol trek berikutnya ke pemutar mini.</string>
|
||||||
<string name="revanced_enable_zen_mode_title">Aktifkan mode zen</string>
|
<string name="revanced_add_miniplayer_previous_button_title">Tambahkan tombol sebelumnya miniplayer</string>
|
||||||
<string name="revanced_enable_zen_mode_summary">Menambahkan rona abu-abu ke pemutar video untuk mengurangi ketegangan mata.</string>
|
<string name="revanced_add_miniplayer_previous_button_summary">Menambahkan tombol trek sebelumnya ke pemutar mini.</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_title">Enable Zen mode in podcasts</string>
|
<string name="revanced_change_miniplayer_color_title">Ubah warna pemutar mini</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_summary">Also enables Zen mode for podcasts.</string>
|
<string name="revanced_change_miniplayer_color_summary">Mengubah warna pemutar mini supaya sesuai dengan pemutar layar penuh.</string>
|
||||||
<string name="revanced_hide_comment_channel_guidelines_title">Hide channel guidelines</string>
|
<string name="revanced_change_player_background_color_title">Ubah warna latar belakang pemutar</string>
|
||||||
<string name="revanced_hide_comment_channel_guidelines_summary">Hides the channel guidelines at the top of the comments section.</string>
|
<string name="revanced_change_player_background_color_summary">Mengubah warna latar belakang pemutar ke warna khusus.</string>
|
||||||
<string name="revanced_hide_double_tap_overlay_filter_title">Sembunyikan filter overlay double-tap</string>
|
<string name="revanced_custom_player_background_color_primary_title">Warna primer latar belakang pemutar</string>
|
||||||
<string name="revanced_hide_double_tap_overlay_filter_summary">Menyembunyikan overlay gelap yang muncul ketika double-tap to seek.</string>
|
<string name="revanced_custom_player_background_color_primary_summary">"Masukkan kode hex dari warna primer latar belakang pemutar.
|
||||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_title">Hide timestamp and emoji buttons</string>
|
|
||||||
|
Gunakan warna gelap jika memungkinkan, karena aplikasi ini tidak mendukung tema terang."</string>
|
||||||
|
<string name="revanced_custom_player_background_color_secondary_title">Warna sekunder latar belakang pemutar</string>
|
||||||
|
<string name="revanced_custom_player_background_color_secondary_summary">"Masukkan kode hex warna sekunder latar belakang pemutar.
|
||||||
|
|
||||||
|
Gunakan warna gelap jika memungkinkan, karena aplikasi ini tidak mendukung tema terang."</string>
|
||||||
|
<string name="revanced_custom_player_background_invalid_toast">Warna latar belakang pemutar tidak sah.</string>
|
||||||
|
<string name="revanced_change_seekbar_position_title">Ubah posisi seekbar</string>
|
||||||
|
<string name="revanced_change_seekbar_position_summary">Memindahkan seekbar di bawah tombol putar.</string>
|
||||||
|
<string name="revanced_disable_miniplayer_gesture_title">Nonaktifkan gerakan pemutar mini</string>
|
||||||
|
<string name="revanced_disable_miniplayer_gesture_summary">Menonaktifkan usapan untuk mengubah trek di pemutar mini.</string>
|
||||||
|
<string name="revanced_disable_player_gesture_title">Nonaktifkan gerakan pemutar</string>
|
||||||
|
<string name="revanced_disable_player_gesture_summary">Menonaktifkan usap untuk mengubah trek di pemutar.</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_title">Aktifkan pemutar mini paksa</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_summary">Mengaktifkan pemutar mini paksa saat beralih ke trek baru.</string>
|
||||||
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">Aktifkan usapan untuk menutup pemutar mini</string>
|
||||||
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">Mengaktifkan gesek ke bawah untuk menutup pemutar mini.</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_title">Aktifkan seekbar tebal</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_summary">"Mengaktifkan seekbar yang tebal.
|
||||||
|
|
||||||
|
Keterbatasan: Segmen SponsorBlock tidak ditampilkan di seekbar."</string>
|
||||||
|
<string name="revanced_enable_zen_mode_title">Aktifkan mode Zen</string>
|
||||||
|
<string name="revanced_enable_zen_mode_summary">Mengaktifkan warna abu-abu muda untuk latar belakang pemutar untuk mengurangi kelelahan mata.</string>
|
||||||
|
<string name="revanced_enable_zen_mode_podcast_title">Aktifkan mode Zen di podcast</string>
|
||||||
|
<string name="revanced_enable_zen_mode_podcast_summary">Mengaktifkan mode Zen di podcast.</string>
|
||||||
|
<string name="revanced_hide_comment_channel_guidelines_title">Sembunyikan pedoman saluran</string>
|
||||||
|
<string name="revanced_hide_comment_channel_guidelines_summary">Menyembunyikan panduan saluran di bagian atas komentar.</string>
|
||||||
|
<string name="revanced_hide_double_tap_overlay_filter_title">Sembunyikan penyaring hamparan ketuk dua kali</string>
|
||||||
|
<string name="revanced_hide_double_tap_overlay_filter_summary">Menyembunyikan hamparan gelap yang muncul ketika mengetuk dua kali untuk menggeser.</string>
|
||||||
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_title">Sembunyikan tombol emoji dan stempel waktu</string>
|
||||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary">Hides the timestamp and emoji buttons when typing comments.</string>
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary">Hides the timestamp and emoji buttons when typing comments.</string>
|
||||||
<string name="revanced_hide_fullscreen_share_button_title">Hide fullscreen Share button</string>
|
<string name="revanced_hide_fullscreen_share_button_title">Sembunyikan tombol Bagikan layar penuh</string>
|
||||||
<string name="revanced_hide_fullscreen_share_button_summary">Hides the Share button in the fullscreen player.</string>
|
<string name="revanced_hide_fullscreen_share_button_summary">Menyembunyikan tombol Bagikan di pemutar layar penuh.</string>
|
||||||
|
<string name="revanced_hide_song_video_toggle_title">Sembunyikan tombol Lagu / Video</string>
|
||||||
|
<string name="revanced_hide_song_video_toggle_summary">Menyembunyikan tombol Lagu / Video di pemutar.</string>
|
||||||
<string name="revanced_remember_repeat_state_title">Ingat keadaan pengulangan</string>
|
<string name="revanced_remember_repeat_state_title">Ingat keadaan pengulangan</string>
|
||||||
<string name="revanced_remember_repeat_state_summary">Mengingat keadaan pengulangan.</string>
|
<string name="revanced_remember_repeat_state_summary">Mengingat keadaan tombol pengulangan.</string>
|
||||||
<string name="revanced_remember_shuffle_state_title">Ingat keadaan pengacakan</string>
|
<string name="revanced_remember_shuffle_state_title">Ingat keadaan pengacakan</string>
|
||||||
<string name="revanced_remember_shuffle_state_summary">Mengingat keadaan pengacakan.</string>
|
<string name="revanced_remember_shuffle_state_summary">Mengingat status tombol pengacakan.</string>
|
||||||
<string name="revanced_restore_old_comments_popup_panels_title">Restore old comments popup panels</string>
|
<string name="revanced_restore_old_comments_popup_panels_title">Pulihkan panel sembulan komentar lama</string>
|
||||||
<string name="revanced_restore_old_comments_popup_panels_summary">Returns the comments popup panels to the old style.</string>
|
<string name="revanced_restore_old_comments_popup_panels_summary">Memulihkan panel sembulan komentar ke gaya lama.</string>
|
||||||
<string name="revanced_restore_old_player_background_title">Restore old player background</string>
|
<string name="revanced_restore_old_player_background_title">Pulihkan latar belakang pemutar lama</string>
|
||||||
<string name="revanced_restore_old_player_background_summary">Returns the player background to the old style.</string>
|
<string name="revanced_restore_old_player_background_summary">Mengembalikan latar belakang pemutar ke gaya lama.</string>
|
||||||
<string name="revanced_restore_old_player_layout_title">Restore old player layout</string>
|
<string name="revanced_restore_old_player_layout_title">Pulihkan tata letak pemutar lama</string>
|
||||||
<string name="revanced_restore_old_player_layout_summary">"Returns the player layout to the old style.
|
<string name="revanced_restore_old_player_layout_summary">"Memulihkan tata letak pemutar ke gaya lama.
|
||||||
Some features may not work properly in the old player layout."</string>
|
Beberapa fitur mungkin tidak berfungsi dengan baik dalam tata letak pemutar lama."</string>
|
||||||
<!-- PreferenceScreen: Settings menu -->
|
<!-- PreferenceScreen: Settings menu -->
|
||||||
|
<string name="revanced_preference_screen_settings_title">Menu pengaturan</string>
|
||||||
|
<string name="revanced_hide_settings_menu_parent_tools_title">Sembunyikan menu Pusat Keluarga</string>
|
||||||
|
<string name="revanced_hide_settings_menu_general_title">Sembunyikan menu Umum</string>
|
||||||
|
<string name="revanced_hide_settings_menu_playback_title">Sembunyikan menu Pemutaran</string>
|
||||||
|
<string name="revanced_hide_settings_menu_data_saving_title">Sembunyikan menu penghematan Data</string>
|
||||||
|
<string name="revanced_hide_settings_menu_downloads_and_storage_title">Sembunyikan menu Unduhan & penyimpanan</string>
|
||||||
|
<string name="revanced_hide_settings_menu_notification_title">Sembunyikan menu Pemberitahuan</string>
|
||||||
|
<string name="revanced_hide_settings_menu_privacy_and_location_title">Sembunyikan menu Privasi & data</string>
|
||||||
|
<string name="revanced_hide_settings_menu_recommendations_title">Sembunyikan menu Rekomendasi</string>
|
||||||
|
<string name="revanced_hide_settings_menu_paid_memberships_title">Sembunyikan menu Dapatkan Music premium</string>
|
||||||
|
<string name="revanced_hide_settings_menu_about_title">Sembunyikan menu Tentang</string>
|
||||||
<!-- PreferenceScreen: Video -->
|
<!-- PreferenceScreen: Video -->
|
||||||
<string name="revanced_preference_screen_video_title">Video</string>
|
<string name="revanced_preference_screen_video_title">Video</string>
|
||||||
<string name="revanced_custom_playback_speeds_title">Edit kecepatan pemutaran kustom</string>
|
<string name="revanced_custom_playback_speeds_title">Edit kecepatan pemutaran khusus</string>
|
||||||
<string name="revanced_custom_playback_speeds_summary">Menambah atau mengubah kecepatan pemutaran yang tersedia.</string>
|
<string name="revanced_custom_playback_speeds_summary">Menambah atau mengubah kecepatan pemutaran yang tersedia.</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_title">Remember playback speed changes</string>
|
<string name="revanced_remember_playback_speed_last_selected_title">Ingat perubahan kecepatan pemutaran</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_summary">Remembers the last playback speed selected.</string>
|
<string name="revanced_remember_playback_speed_last_selected_summary">Remembers the last playback speed selected.</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_toast_title">Tampilkan toast</string>
|
<string name="revanced_remember_playback_speed_last_selected_toast_title">Tampilkan toast</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_toast_summary">Menunjukkan toast ketika mengubah playback speed semula.</string>
|
<string name="revanced_remember_playback_speed_last_selected_toast_summary">Menampilkan toast saat mengubah kecepatan pemutaran bawaan.</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_title">Remember video quality changes</string>
|
<string name="revanced_remember_video_quality_last_selected_title">Ingat perubahan kualitas video</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_summary">Remembers the last video quality selected.</string>
|
<string name="revanced_remember_video_quality_last_selected_summary">Mengingat kualitas video terakhir yang dipilih.</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_toast_title">Tampilkan toast</string>
|
<string name="revanced_remember_video_quality_last_selected_toast_title">Tampilkan toast</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_toast_summary">Menunjukkan toast ketika mengubah playback speed semula.</string>
|
<string name="revanced_remember_video_quality_last_selected_toast_summary">Menampilkan toast ketika mengubah kualitas video bawaan.</string>
|
||||||
<string name="revanced_custom_playback_speeds_invalid">Kecepatan pemutaran kustom tidak valid. Atur ulang ke nilai default.</string>
|
<string name="revanced_custom_playback_speeds_invalid">Kecepatan khusus harus kurang dari %sx.</string>
|
||||||
<string name="revanced_custom_playback_speeds_parse_exception">Invalid custom playback speeds. Using default values.</string>
|
<string name="revanced_custom_playback_speeds_parse_exception">Kecepatan pemutaran kustom tidak sah.</string>
|
||||||
<string name="revanced_remember_playback_speed_toast">Changing default speed to %s.</string>
|
<string name="revanced_remember_playback_speed_toast">Mengubah kecepatan bawaan ke %s.</string>
|
||||||
<string name="revanced_remember_video_quality_mobile">Changing default mobile data quality to %s.</string>
|
<string name="revanced_remember_video_quality_mobile">Mengubah kualitas data seluler bawaan ke %s.</string>
|
||||||
<string name="revanced_remember_video_quality_none">Failed to set quality.</string>
|
<string name="revanced_remember_video_quality_none">Gagal mengatur kualitas.</string>
|
||||||
<string name="revanced_remember_video_quality_wifi">Changing default Wi-Fi quality to %s.</string>
|
<string name="revanced_remember_video_quality_wifi">Mengubah kualitas Wi-Fi bawaan ke %s.</string>
|
||||||
<!-- PreferenceScreen: Return YouTube Dislike -->
|
<!-- PreferenceScreen: Return YouTube Dislike -->
|
||||||
<string name="revanced_preference_screen_ryd_title">Return YouTube Dislike</string>
|
<string name="revanced_preference_screen_ryd_title">Return YouTube Dislike</string>
|
||||||
<string name="revanced_ryd_enabled_title">Enable Return YouTube Dislike</string>
|
<string name="revanced_ryd_enabled_title">Aktifkan Return YouTube Dislike</string>
|
||||||
<string name="revanced_ryd_enabled_summary">Menunjukkan jumlah dislike pada video.</string>
|
<string name="revanced_ryd_enabled_summary">Menampilkan jumlah tidak suka pada video.</string>
|
||||||
<string name="revanced_ryd_dislike_percentage_title">Dislike sebagai persentase</string>
|
<string name="revanced_ryd_dislike_percentage_title">Dislike sebagai persentase</string>
|
||||||
<string name="revanced_ryd_dislike_percentage_summary">Alih-alih jumlah dislike, yang ditampilkan adalah persentase dislike.</string>
|
<string name="revanced_ryd_dislike_percentage_summary">Menampilkan persentase dislike, bukan jumlah dislike.</string>
|
||||||
<string name="revanced_ryd_compact_layout_title">Tombol like ringkas</string>
|
<string name="revanced_ryd_compact_layout_title">Tombol suka ringkas</string>
|
||||||
<string name="revanced_ryd_compact_layout_summary">Menyembunyikan pemisah tombol like.</string>
|
<string name="revanced_ryd_compact_layout_summary">Menyembunyikan pemisah tombol suka.</string>
|
||||||
<string name="revanced_ryd_toast_on_connection_error_title">Show a toast if API is unavailable</string>
|
<string name="revanced_ryd_estimated_like_title">Tampilkan perkiraan suka</string>
|
||||||
<string name="revanced_ryd_toast_on_connection_error_summary">Shows a toast if the Return YouTube Dislike API is unavailable.</string>
|
<string name="revanced_ryd_estimated_like_summary">Menampilkan perkiraan jumlah suka video.</string>
|
||||||
|
<string name="revanced_ryd_toast_on_connection_error_title">Tampilkan toast jika API tidak tersedia</string>
|
||||||
|
<string name="revanced_ryd_toast_on_connection_error_summary">Menampilkan toast jika API Return YouTube Dislike tidak tersedia.</string>
|
||||||
<string name="revanced_ryd_about">Tentang</string>
|
<string name="revanced_ryd_about">Tentang</string>
|
||||||
<string name="revanced_ryd_attribution_title">ReturnYouTubeDislike.com</string>
|
<string name="revanced_ryd_attribution_title">ReturnYouTubeDislike.com</string>
|
||||||
<string name="revanced_ryd_attribution_summary">Data disediakan oleh API Return YouTube Dislike. Tekan di sini untuk mempelajari lebih lanjut.</string>
|
<string name="revanced_ryd_attribution_summary">Data disediakan oleh API Return YouTube Dislike. Tekan di sini untuk mempelajari lebih lanjut.</string>
|
||||||
<string name="revanced_ryd_failure_connection_timeout">Dislikes are temporarily unavailable (API timed out).</string>
|
<string name="revanced_ryd_failure_connection_timeout">Dislike untuk sementara tidak tersedia (API kehabisan waktu).</string>
|
||||||
<string name="revanced_ryd_failure_connection_status_code">Dislikes are unavailable (status %d).</string>
|
<string name="revanced_ryd_failure_connection_status_code">Dislike tidak tersedia (status %d).</string>
|
||||||
<string name="revanced_ryd_failure_client_rate_limit_requested">Dislike tidak tersedia (batas API client tercapai).</string>
|
<string name="revanced_ryd_failure_client_rate_limit_requested">Dislike tidak tersedia (batas API client tercapai).</string>
|
||||||
<string name="revanced_ryd_failure_generic">Dislikes are unavailable (%s).</string>
|
<string name="revanced_ryd_failure_generic">Dislikes tidak tersedia (%s).</string>
|
||||||
|
<string name="revanced_ryd_video_likes_hidden_by_video_owner">Disembunyikan</string>
|
||||||
<!-- PreferenceScreen: Return YouTube Username -->
|
<!-- PreferenceScreen: Return YouTube Username -->
|
||||||
|
<string name="revanced_preference_screen_return_youtube_username_title">Return YouTube Username</string>
|
||||||
|
<string name="revanced_return_youtube_username_enabled_title">Aktifkan Return YouTube Username</string>
|
||||||
|
<string name="revanced_return_youtube_username_enabled_summary">Mengganti penanganan dengan nama pengguna di komentar.</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_title">Format tampilan</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_summary">Pilih format tampilan nama pengguna.</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_username_only">Nama pengguna</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_username_handle">Nama pengguna (@penganganan)</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_handle_username">\@penanganan (Nama pengguna)</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_developer_key_title">Kunci API Data YouTube</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_developer_key_summary">Kunci pengembang untuk menggunakan API Data YouTube v3.</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_about_title">Tentang kunci API Data YouTube</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_about_summary">"Kunci Pengembang API Data YouTube v3 diperlukan untuk mengganti penanganan dengan nama pengguna.
|
||||||
|
|
||||||
|
Kuota harian untuk kunci API pada paket gratis adalah 10.000, dan 1 kuota digunakan untuk mengganti penanganan dengan nama pengguna untuk 1 komentar.
|
||||||
|
|
||||||
|
Klik untuk melihat cara menerbitkan kunci API."</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_dialog_title">Terbitkan kunci pengembang API Data YouTube v3</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_dialog_message">1. Pergi ke <a href=%1$s>Buat proyek baru</a>.<br>2. Klik <b>tombol;</b> BUAT.<br>3. Pergi ke <a href=%2$s>API Data YouTube v3</a>.<br>4. Klik <b>tombol</b> NYALAKAN.<br>5. Klik <b>tombol</b> BUAT KREDENSIAL.<br>6. Pilih <b>pilihan</b> data Publik.<br>7. Klik <b>tombol</b> SELANJUTNYA.<br>8. Salin kunci API.<br><br>※ Kunci API tidak boleh dibagikan dengan orang lain, sehingga tidak disertakan dalam pengaturan Impor / Ekspor.</string>
|
||||||
<!-- PreferenceScreen: SponsorBlock -->
|
<!-- PreferenceScreen: SponsorBlock -->
|
||||||
<string name="revanced_preference_screen_sb_title">SponsorBlock</string>
|
<string name="revanced_preference_screen_sb_title">SponsorBlock</string>
|
||||||
<string name="revanced_sb_enabled">Enable SponsorBlock</string>
|
<string name="revanced_sb_enabled">Aktifkan SponsorBlock</string>
|
||||||
<string name="revanced_sb_enabled_sum">SponsorBlock is a crowd-sourced system for skipping annoying parts of YouTube videos.</string>
|
<string name="revanced_sb_enabled_sum">SponsorBlock adalah sistem yang bersumber dari banyak orang untuk melewatkan bagian video YouTube yang mengganggu.</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error">Show a toast if API is unavailable</string>
|
<string name="revanced_sb_toast_on_connection_error">Tampilkan toast jika API tidak tersedia</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error_sum">Shows a toast if the SponsorBlock API is unavailable.</string>
|
<string name="revanced_sb_toast_on_connection_error_sum">Menampilkan toast jika API SponsorBlock tidak tersedia.</string>
|
||||||
<string name="revanced_sb_toast_on_skip">Show a toast when skipping automatically</string>
|
<string name="revanced_sb_toast_on_skip">Menampilkan toast saat melewatkan secara otomatis</string>
|
||||||
<string name="revanced_sb_toast_on_skip_sum">Shows a toast when a segment is automatically skipped.</string>
|
<string name="revanced_sb_toast_on_skip_sum">Menampilkan toast ketika segmen dilewati secara otomatis.</string>
|
||||||
<string name="revanced_sb_api_url">Change API URL</string>
|
<string name="revanced_sb_api_url">Ubah URL API</string>
|
||||||
<string name="revanced_sb_api_url_sum">The address SponsorBlock uses to make calls to the server. Do not change this unless you know what you\'re doing.</string>
|
<string name="revanced_sb_api_url_sum">Alamat yang digunakan SponsorBlock untuk melakukan panggilan ke server. Jangan ubah ini kecuali Anda tahu apa yang Anda lakukan.</string>
|
||||||
<string name="revanced_sb_api_url_reset">API URL reset.</string>
|
<string name="revanced_sb_api_url_reset">URL API diatur ulang.</string>
|
||||||
<string name="revanced_sb_api_url_invalid">API URL is invalid.</string>
|
<string name="revanced_sb_api_url_invalid">URL API tidak sah.</string>
|
||||||
<string name="revanced_sb_api_url_changed">API URL changed.</string>
|
<string name="revanced_sb_api_url_changed">URL API diubah.</string>
|
||||||
<string name="revanced_sb_diff_segments">Change segment behavior</string>
|
<string name="revanced_sb_diff_segments">Ubah perilaku segmen</string>
|
||||||
<string name="revanced_sb_segments_sponsor">Sponsor</string>
|
<string name="revanced_sb_segments_sponsor">Sponsor</string>
|
||||||
<string name="revanced_sb_segments_sponsor_sum">Paid promotion, paid referrals, and direct advertisements. Not for self-promotion or free shout-outs to causes / creators / websites / products they like.</string>
|
<string name="revanced_sb_segments_sponsor_sum">Promosi berbayar, rujukan berbayar, dan iklan langsung. Bukan untuk promosi diri atau promosi gratis untuk tujuan / kreator / situs web / produk yang mereka sukai.</string>
|
||||||
<string name="revanced_sb_segments_selfpromo">Unpaid / Self Promotion</string>
|
<string name="revanced_sb_segments_selfpromo">Tidak Berbayar / Promosi Sendiri</string>
|
||||||
<string name="revanced_sb_segments_selfpromo_sum">Similar to \'Sponsor\' except for unpaid or self promotion. Includes sections about merchandise, donations, or information about who they collaborated with.</string>
|
<string name="revanced_sb_segments_selfpromo_sum">Mirip dengan Sponsor, kecuali untuk promosi yang tidak berbayar atau promosi sendiri. Termasuk bagian tentang barang dagangan, donasi, atau informasi tentang dengan siapa mereka berkolaborasi.</string>
|
||||||
<string name="revanced_sb_segments_interaction">Interaction Reminder (Subscribe)</string>
|
<string name="revanced_sb_segments_interaction">Pengingat Interaksi (Berlangganan)</string>
|
||||||
<string name="revanced_sb_segments_interaction_sum">A short reminder to like, subscribe, or follow them in the middle of content. If it is long or about something specific, it should instead be under self promotion.</string>
|
<string name="revanced_sb_segments_interaction_sum">Pengingat singkat untuk menyukai, berlangganan, atau mengikuti mereka di tengah-tengah konten. Jika panjang atau tentang sesuatu yang spesifik, sebaiknya berada di bawah promosi diri.</string>
|
||||||
<string name="revanced_sb_segments_intro">Intermission / Intro Animation</string>
|
<string name="revanced_sb_segments_intro">Animasi Jeda / Intro</string>
|
||||||
<string name="revanced_sb_segments_intro_sum">An interval without actual content. Could be a pause, static frame, or repeating animation. Does not include transitions containing information.</string>
|
<string name="revanced_sb_segments_intro_sum">Selang waktu tanpa konten yang sebenarnya. Bisa berupa jeda, bingkai statis, atau animasi berulang. Tidak termasuk transisi yang berisi informasi.</string>
|
||||||
<string name="revanced_sb_segments_outro">Endcards / Credits</string>
|
<string name="revanced_sb_segments_outro">Kartu Akhir / Kredit</string>
|
||||||
<string name="revanced_sb_segments_outro_sum">Credits or when the YouTube endcards appear. Not for conclusions with information.</string>
|
<string name="revanced_sb_segments_outro_sum">Kredit atau saat kartu akhir YouTube muncul. Bukan untuk menyimpulkan informasi.</string>
|
||||||
<string name="revanced_sb_segments_preview">Preview / Recap / Hook</string>
|
<string name="revanced_sb_segments_preview">Pratinjau / Rekap / Pengait</string>
|
||||||
<string name="revanced_sb_segments_preview_sum">Collection of clips that show what is coming up or what happened in the video or in other videos of a series, where all information is repeated elsewhere.</string>
|
<string name="revanced_sb_segments_preview_sum">Kumpulan klip yang menunjukkan apa yang akan datang atau apa yang terjadi dalam video atau dalam video lain dari suatu seri, di mana semua informasi diulang di tempat lain.</string>
|
||||||
<string name="revanced_sb_segments_filler">Filler Tangent / Jokes</string>
|
<string name="revanced_sb_segments_filler">Pengisi Tidak Relevan / Lelucon</string>
|
||||||
<string name="revanced_sb_segments_filler_sum">Tangential scenes added only for filler or humor that are not required to understand the main content of the video. Does not include segments providing context or background details.</string>
|
<string name="revanced_sb_segments_filler_sum">Adegan berbelit-belit yang ditambahkan hanya sebagai filler atau candaan yang tidak diperlukan untuk memahami isi utama video. Tidak termasuk bagian yang mengandung konteks atau detail latar belakang.</string>
|
||||||
<string name="revanced_sb_segments_nomusic">Music: Non-Music Section</string>
|
<string name="revanced_sb_segments_nomusic">Musik: Bagian Non-Musik</string>
|
||||||
<string name="revanced_sb_segments_nomusic_sum">Only for use in music videos. Sections of music videos without music, that aren\'t already covered by another category.</string>
|
<string name="revanced_sb_segments_nomusic_sum">Hanya untuk digunakan dalam video musik. Bagian video musik tanpa musik, yang belum tercakup dalam kategori lain.</string>
|
||||||
<string name="revanced_sb_skipped_sponsor">Skipped sponsor.</string>
|
<string name="revanced_sb_skipped_sponsor">Melewatkan sponsor.</string>
|
||||||
<string name="revanced_sb_skipped_selfpromo">Skipped self promotion.</string>
|
<string name="revanced_sb_skipped_selfpromo">Melewatkan promosi diri.</string>
|
||||||
<string name="revanced_sb_skipped_interaction">Skipped annoying reminder.</string>
|
<string name="revanced_sb_skipped_interaction">Melewatkan pengingat mengganggu.</string>
|
||||||
<string name="revanced_sb_skipped_intro_beginning">Skipped intro.</string>
|
<string name="revanced_sb_skipped_intro_beginning">Melewatkan intro.</string>
|
||||||
<string name="revanced_sb_skipped_intro_middle">Skipped intermission.</string>
|
<string name="revanced_sb_skipped_intro_middle">Melewatkan jeda.</string>
|
||||||
<string name="revanced_sb_skipped_intro_end">Skipped intermission.</string>
|
<string name="revanced_sb_skipped_intro_end">Melewatkan jeda.</string>
|
||||||
<string name="revanced_sb_skipped_outro">Skipped outro.</string>
|
<string name="revanced_sb_skipped_outro">Melewatkan outro.</string>
|
||||||
<string name="revanced_sb_skipped_preview_beginning">Skipped preview.</string>
|
<string name="revanced_sb_skipped_preview_beginning">Melewatkan pratinjau.</string>
|
||||||
<string name="revanced_sb_skipped_preview_middle">Skipped preview.</string>
|
<string name="revanced_sb_skipped_preview_middle">Melewatkan pratinjau.</string>
|
||||||
<string name="revanced_sb_skipped_preview_end">Skipped recap.</string>
|
<string name="revanced_sb_skipped_preview_end">Melewatkan rekap.</string>
|
||||||
<string name="revanced_sb_skipped_filler">Skipped filler.</string>
|
<string name="revanced_sb_skipped_filler">Melewatkan pengisi.</string>
|
||||||
<string name="revanced_sb_skipped_nomusic">Skipped a non-music section.</string>
|
<string name="revanced_sb_skipped_nomusic">Melewatkan bagian non musik.</string>
|
||||||
<string name="revanced_sb_skipped_multiple_segments">Skipped multiple segments.</string>
|
<string name="revanced_sb_skipped_multiple_segments">Melewatkan beberapa segmen.</string>
|
||||||
<string name="revanced_sb_skip_automatically">Skip automatically</string>
|
<string name="revanced_sb_skip_automatically">Lewati otomatis</string>
|
||||||
<string name="revanced_sb_skip_ignore">Disable</string>
|
<string name="revanced_sb_skip_ignore">Nonaktifkan</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlock is temporarily unavailable.</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlock untuk sementara tidak tersedia.</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlock is temporarily unavailable (status %d).</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlock untuk sementara tidak tersedia (status %d).</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_timeout">SponsorBlock is temporarily unavailable (API timed out).</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_timeout">SponsorBlock untuk sementara tidak tersedia (API habis batas waktunya).</string>
|
||||||
<string name="revanced_sb_color_dot_label">Color:</string>
|
<string name="revanced_sb_color_dot_label">Warna:</string>
|
||||||
<string name="revanced_sb_color_changed">Color changed.</string>
|
<string name="revanced_sb_color_changed">Warna diubah.</string>
|
||||||
<string name="revanced_sb_color_reset">Color reset.</string>
|
<string name="revanced_sb_color_reset">Warna diatur ulang.</string>
|
||||||
<string name="revanced_sb_color_invalid">Invalid color code. Color reset to default.</string>
|
<string name="revanced_sb_color_invalid">Kode warna tidak sah.</string>
|
||||||
<string name="revanced_sb_reset_color">Reset color</string>
|
<string name="revanced_sb_reset_color">Atur ulang warna</string>
|
||||||
<string name="revanced_sb_about_api_sum">Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms.</string>
|
<string name="revanced_sb_about_api_sum">Data disediakan oleh API SponsorBlock. Tekan di sini untuk mempelajari lebih lanjut dan melihat unduhan untuk platform lain.</string>
|
||||||
<string name="revanced_sb_about">About</string>
|
<string name="revanced_sb_about">Tentang</string>
|
||||||
<string name="revanced_sb_about_api">sponsor.ajay.app</string>
|
<string name="revanced_sb_about_api">sponsor.ajay.app</string>
|
||||||
<!-- PreferenceScreen: Miscellaneous -->
|
<!-- PreferenceScreen: Miscellaneous -->
|
||||||
<string name="revanced_preference_screen_misc_title">Miscellaneous</string>
|
<string name="revanced_preference_screen_misc_title">Lain-lain</string>
|
||||||
<string name="revanced_extended_settings_import_export_title">Ekspor / Impor</string>
|
<string name="revanced_extended_settings_import_export_title">Ekspor / Impor</string>
|
||||||
<string name="revanced_extended_settings_import_export_summary">Impor atau ekspor setelan sebagai teks.</string>
|
<string name="revanced_extended_settings_import_export_summary">Impor / Ekspor pengaturan Musik RVX.</string>
|
||||||
<string name="revanced_extended_settings_export_as_file">Export settings to file</string>
|
<string name="revanced_extended_settings_export_as_file">Ekspor pengaturan ke berkas</string>
|
||||||
<string name="revanced_extended_settings_import_as_file">Import settings from file</string>
|
<string name="revanced_extended_settings_import_as_file">Impor pengaturan dari berkas</string>
|
||||||
<string name="revanced_extended_settings_import_export_as_text">Import / Export settings as text</string>
|
<string name="revanced_extended_settings_import_export_as_text">Impor / Ekspor pengaturan sebagai teks</string>
|
||||||
<string name="revanced_extended_settings_export_failed">Failed to export settings.</string>
|
<string name="revanced_extended_settings_export_failed">Gagal mengekspor pengaturan.</string>
|
||||||
<string name="revanced_extended_settings_export_success">Settings were successfully exported.</string>
|
<string name="revanced_extended_settings_export_success">Pengaturan berhasil diekspor.</string>
|
||||||
<string name="revanced_extended_settings_import">Impor</string>
|
<string name="revanced_extended_settings_import">Impor</string>
|
||||||
<string name="revanced_extended_settings_import_copy">Salin</string>
|
<string name="revanced_extended_settings_import_copy">Salin</string>
|
||||||
<string name="revanced_extended_settings_import_failed">Import failed: %s.</string>
|
<string name="revanced_extended_settings_import_failed">Impor gagal: %s.</string>
|
||||||
<string name="revanced_extended_settings_import_reset">Reset setelan ke default.</string>
|
<string name="revanced_extended_settings_import_reset">Pengaturan diatur ulang ke bawaan.</string>
|
||||||
<string name="revanced_extended_settings_import_success">Setelan %d diimpor.</string>
|
<string name="revanced_extended_settings_import_success">Setelan %d diimpor.</string>
|
||||||
<string name="revanced_extended_settings_reset">Reset</string>
|
<string name="revanced_extended_settings_reset">Atur ulang</string>
|
||||||
<string name="revanced_share_copy_settings_success">Setelan disalin ke papan klip.</string>
|
<string name="revanced_share_copy_settings_success">Setelan disalin ke papan klip.</string>
|
||||||
<string name="revanced_bypass_image_region_restrictions_title">Bypass gambar larangan wilayah</string>
|
<string name="revanced_bypass_image_region_restrictions_title">Abaikan pembatasan wilayah gambar</string>
|
||||||
<string name="revanced_bypass_image_region_restrictions_summary">Mengganti domain yang ke blokir di negara tertentu sehingga playlist thumbnail, channel avatar, dll bisa di terima.</string>
|
<string name="revanced_bypass_image_region_restrictions_summary">Mengabaikan domain yang diblokir di beberapa wilayah sehingga thumbnail playlist, avatar saluran, dll. dapat diterima.</string>
|
||||||
<string name="revanced_change_share_sheet_title">Ubah lembar berbagi</string>
|
<string name="revanced_change_share_sheet_title">Ubah lembar berbagi</string>
|
||||||
<string name="revanced_change_share_sheet_summary">Mengubah dari lembar berbagi dalam aplikasi ke lembar berbagi sistem.</string>
|
<string name="revanced_change_share_sheet_summary">Mengubah lembar berbagi dalam aplikasi ke lembar berbagi sistem.</string>
|
||||||
|
<string name="revanced_disable_cairo_splash_animation_title">Menonaktifkan animasi percikan Cairo</string>
|
||||||
|
<string name="revanced_disable_cairo_splash_animation_summary">Menonaktifkan animasi percikan Cairo saat aplikasi dimulai.</string>
|
||||||
|
<string name="revanced_disable_drc_audio_title">Nonaktifkan audio DRC</string>
|
||||||
|
<string name="revanced_disable_drc_audio_summary">Menonaktifkan DRC (Dynamic Range Compression) yang diterapkan ke audio.</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_title">Nonaktifkan video musik dalam album</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_summary">"Ketika pengguna non-premium memutar lagu yang termasuk dalam album, video musik terkadang diputar dan bukannya lagu resminya.
|
||||||
|
|
||||||
|
Temukan lagu resmi jika video musik terdeteksi diputar dari album.
|
||||||
|
|
||||||
|
Keterbatasan: Video anak-anak mungkin tidak dapat dialihkan."</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_title">Jenis pengalihan</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_summary">Menentukan cara mengalihkan ke lagu resmi.</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">Alihkan</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">Ketuk tombol Lagu / Video</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">Ketuk dan tahan tombol Lagu / Video</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_title">Nonaktifkan protokol QUIC</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_summary">"Menonaktifkan protokol QUIC CronetEngine."</string>
|
||||||
<string name="revanced_enable_debug_logging_title">Aktifkan pencatatan debug</string>
|
<string name="revanced_enable_debug_logging_title">Aktifkan pencatatan debug</string>
|
||||||
<string name="revanced_enable_debug_logging_summary">Mencetak catatan debug.</string>
|
<string name="revanced_enable_debug_logging_summary">Mencetak catatan debug.</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_title">Enable debug buffer logging</string>
|
<string name="revanced_enable_debug_buffer_logging_title">Mengaktifkan pencatatan buffer debug</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_summary">Includes the buffer in the debug log.</string>
|
<string name="revanced_enable_debug_buffer_logging_summary">Menyertakan buffer dalam log debug.</string>
|
||||||
<string name="revanced_enable_opus_codec_title">Aktifkan codec opus</string>
|
<string name="revanced_enable_opus_codec_title">Aktifkan codec opus</string>
|
||||||
<string name="revanced_enable_opus_codec_summary">"Mengaktifkan codec audio opus alih-alih codec audio mp4a."</string>
|
<string name="revanced_enable_opus_codec_summary">"Mengaktifkan codec OPUS jika respon pemutar menyertakannya.
|
||||||
<string name="revanced_sanitize_sharing_links_title">Sanitasi tautan berbagi</string>
|
|
||||||
<string name="revanced_sanitize_sharing_links_summary">Menghapus parameter kueri pelacakan dari URL saat membagikan tautan.</string>
|
|
||||||
<string name="gms_core_settings_title">Open GmsCore</string>
|
|
||||||
<string name="gms_core_settings_summary">Enable cloud messaging to receive notifications.</string>
|
|
||||||
<string name="gms_core_toast_not_installed_message">GmsCore is not installed. Install it.</string>
|
|
||||||
<string name="gms_core_dialog_title">Action needed</string>
|
|
||||||
<string name="gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"GmsCore does not have permission to run in the background.
|
|
||||||
|
|
||||||
Follow the 'Don't kill my app!' guide for your device, and apply the instructions to your GmsCore installation.
|
Info:
|
||||||
|
• Klien YouTube Music terbaru menggunakan codec audio OPUS secara default.
|
||||||
|
• Ini hanya berlaku untuk pengguna yang memalsukan dengan klien yang sangat lama."</string>
|
||||||
|
<string name="revanced_sanitize_sharing_links_title">Bersihkan tautan berbagi</string>
|
||||||
|
<string name="revanced_sanitize_sharing_links_summary">Membersihkan tautan berbagi dengan menghapus parameter kueri pelacakan.</string>
|
||||||
|
<string name="revanced_spoof_client_title">Palsukan klien</string>
|
||||||
|
<string name="revanced_spoof_client_summary">Memalsukan klien untuk mencegah masalah pemutaran.</string>
|
||||||
|
<string name="revanced_spoof_client_type_title">Klien bawaan</string>
|
||||||
|
<string name="revanced_spoof_client_type_summary">Menentukan klien bawaan untuk pemalsuan.</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_android_music_4_27">Musik Android 4.27.53</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Musik Android 5.29.53</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">Musik iOS 6.21</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">Musik iOS 7.04</string>
|
||||||
|
<string name="revanced_watch_history_type_title">Jenis riwayat tontonan</string>
|
||||||
|
<string name="revanced_watch_history_type_summary">"• Asli: Mengikuti pengaturan riwayat tontonan akun Google, tetapi riwayat tontonan mungkin tidak berfungsi karena DNS atau VPN.
|
||||||
|
• Ganti domain: Mengikuti pengaturan riwayat tontonan akun Google.
|
||||||
|
• Blokir riwayat tontonan: Riwayat tontonan diblokir."</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_1">Asli</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_2">Ganti domain</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_3">Blokir riwayat tontonan</string>
|
||||||
|
<string name="revanced_default_app_settings_title">Buka pengaturan aplikasi bawaan</string>
|
||||||
|
<string name="revanced_default_app_settings_summary">Untuk membuka tautan YouTube Music di RVX Music, aktifkan Buka tautan yang didukung dan aktifkan semua alamat web yang Didukung.</string>
|
||||||
|
<string name="gms_core_settings_title">Buka pengaturan GmsCore</string>
|
||||||
|
<string name="gms_core_settings_summary">Untuk menerima pemberitahuan di RVX Music, aktifkan Cloud Messaging.</string>
|
||||||
|
<string name="gms_core_toast_not_installed_message">GmsCore tidak terpasang. Pasang dulu.</string>
|
||||||
|
<string name="gms_core_dialog_title">Diperlukan tindakan</string>
|
||||||
|
<string name="gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"GmsCore tidak memiliki izin untuk berjalan di latar belakang.
|
||||||
|
|
||||||
This is required for the app to work."</string>
|
Ikuti panduan 'Don't kill my app!' untuk perangkat Anda, dan terapkan petunjuk pada pemasangan GmsCore.
|
||||||
<string name="gms_core_dialog_open_website_text">Open website</string>
|
|
||||||
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"GmsCore battery optimizations must be disabled to prevent issues.
|
|
||||||
|
|
||||||
Tap on the continue button and disable battery optimizations."</string>
|
Hal ini diperlukan agar aplikasi dapat berfungsi."</string>
|
||||||
<string name="gms_core_dialog_continue_text">Continue</string>
|
<string name="gms_core_dialog_open_website_text">Buka website</string>
|
||||||
|
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"Pengoptimalan baterai GmsCore harus dinonaktifkan untuk mencegah masalah.
|
||||||
|
|
||||||
|
Menonaktifkan pengoptimalan baterai untuk GmsCore tidak akan berdampak negatif pada penggunaan baterai.
|
||||||
|
|
||||||
|
Ketuk tombol lanjutkan dan izinkan perubahan pengoptimalan."</string>
|
||||||
|
<string name="gms_core_dialog_continue_text">Lanjutkan</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
<string name="revanced_extended_settings_title">RVX</string>
|
<string name="revanced_extended_settings_title">RVX</string>
|
||||||
<string name="revanced_extended_reset_to_default_toast">Atur ulang ke nilai default.</string>
|
<string name="revanced_extended_reset_to_default_toast">Atur ulang ke nilai default.</string>
|
||||||
<!-- Shared Category -->
|
<!-- Shared Category -->
|
||||||
<string name="revanced_extended_restart_first_run">Mulai ulang untuk memuat layout secara normal</string>
|
<string name="revanced_extended_restart_first_run">Mulai ulang untuk memuat tata letak secara normal</string>
|
||||||
<string name="revanced_extended_restart_message">Refresh dan mulai ulang</string>
|
<string name="revanced_extended_restart_message">Segarkan dan mulai ulang</string>
|
||||||
<!-- PreferenceScreen: Account -->
|
<!-- PreferenceScreen: Account -->
|
||||||
<string name="revanced_preference_screen_account_title">Akun</string>
|
<string name="revanced_preference_screen_account_title">Akun</string>
|
||||||
<string name="revanced_hide_account_menu_title">Sembunyikan menu akun</string>
|
<string name="revanced_hide_account_menu_title">Sembunyikan menu akun</string>
|
||||||
<string name="revanced_hide_account_menu_summary">Menyembunyikan elemen menu akun menggunakan filter custom.</string>
|
<string name="revanced_hide_account_menu_summary">Menyembunyikan elemen menu akun menggunakan penyaring khusus.</string>
|
||||||
<string name="revanced_hide_account_menu_filter_strings_title">Filter menu Akun</string>
|
<string name="revanced_hide_account_menu_filter_strings_title">Penyaring menu Akun</string>
|
||||||
<string name="revanced_hide_account_menu_filter_strings_summary">Daftar dari nama-nama menu akun ke filter, terpisah oleh garis baru.</string>
|
<string name="revanced_hide_account_menu_filter_strings_summary">Daftar nama menu akun yang akan disaring, dipisahkan dengan baris baru.</string>
|
||||||
<string name="revanced_hide_account_menu_empty_component_title">Sembunyikan komponen kosong</string>
|
<string name="revanced_hide_account_menu_empty_component_title">Sembunyikan komponen kosong</string>
|
||||||
<string name="revanced_hide_account_menu_empty_component_summary">Menyembunyikan komponen kosong di menu akun.</string>
|
<string name="revanced_hide_account_menu_empty_component_summary">Menyembunyikan komponen kosong di menu akun.</string>
|
||||||
<string name="revanced_hide_handle_title">Sembunyikan handle</string>
|
<string name="revanced_hide_handle_title">Sembunyikan handle</string>
|
||||||
@ -20,13 +20,13 @@
|
|||||||
<string name="revanced_hide_terms_container_summary">Menyembunyikan kontainer ketentuan layanan.</string>
|
<string name="revanced_hide_terms_container_summary">Menyembunyikan kontainer ketentuan layanan.</string>
|
||||||
<!-- PreferenceScreen: Action bar -->
|
<!-- PreferenceScreen: Action bar -->
|
||||||
<string name="revanced_preference_screen_action_bar_title">Bilah Tindakan</string>
|
<string name="revanced_preference_screen_action_bar_title">Bilah Tindakan</string>
|
||||||
<string name="revanced_change_action_bar_position_title">Ubah posisi bilah aksi</string>
|
<string name="revanced_change_action_bar_position_title">Ubah posisi bilah tindakan</string>
|
||||||
<string name="revanced_change_action_bar_position_summary">Pindahkan bilah aksi di bawah tombol putar.</string>
|
<string name="revanced_change_action_bar_position_summary">Pindahkan bilah tindakan di bawah tombol putar.</string>
|
||||||
<string name="revanced_hide_action_button_like_dislike_title">Sembunyikan tombol Like dan Dislike</string>
|
<string name="revanced_hide_action_button_like_dislike_title">Sembunyikan tombol Suka dan Tidak suka</string>
|
||||||
<string name="revanced_hide_action_button_like_dislike_summary">Menyembunyikan tombol Like dan Dislike. Itu tidak akan bekerja di layout player lama.</string>
|
<string name="revanced_hide_action_button_like_dislike_summary">Menyembunyikan tombol Suka dan Tidak suka. Itu tidak akan bekerja di tata letak pemutar lama.</string>
|
||||||
<string name="revanced_hide_action_button_comment_title">Sembunyikan tombol Komentar</string>
|
<string name="revanced_hide_action_button_comment_title">Sembunyikan tombol Komentar</string>
|
||||||
<string name="revanced_hide_action_button_comment_summary">Menyembunyikan tombol Komentar.</string>
|
<string name="revanced_hide_action_button_comment_summary">Menyembunyikan tombol Komentar.</string>
|
||||||
<string name="revanced_hide_action_button_add_to_playlist_title">Sembunyikan tombol Save</string>
|
<string name="revanced_hide_action_button_add_to_playlist_title">Sembunyikan tombol Simpan</string>
|
||||||
<string name="revanced_hide_action_button_add_to_playlist_summary">Menyembunyikan tombol Simpan.</string>
|
<string name="revanced_hide_action_button_add_to_playlist_summary">Menyembunyikan tombol Simpan.</string>
|
||||||
<string name="revanced_hide_action_button_download_title">Sembunyikan tombol Unduh</string>
|
<string name="revanced_hide_action_button_download_title">Sembunyikan tombol Unduh</string>
|
||||||
<string name="revanced_hide_action_button_download_summary">Menyembunyikan tombol Unduh.</string>
|
<string name="revanced_hide_action_button_download_summary">Menyembunyikan tombol Unduh.</string>
|
||||||
@ -37,27 +37,31 @@
|
|||||||
<string name="revanced_hide_action_button_song_video_title">Sembunyikan tombol Lagu / Video</string>
|
<string name="revanced_hide_action_button_song_video_title">Sembunyikan tombol Lagu / Video</string>
|
||||||
<string name="revanced_hide_action_button_song_video_summary">"Sembunyikan tombol Lagu / Video.
|
<string name="revanced_hide_action_button_song_video_summary">"Sembunyikan tombol Lagu / Video.
|
||||||
(Tombol ini hanya tersedia untuk sebagian pengguna)"</string>
|
(Tombol ini hanya tersedia untuk sebagian pengguna)"</string>
|
||||||
<string name="revanced_hide_action_button_label_title">Sembunyikan tombol bilah tindakan</string>
|
<string name="revanced_hide_action_button_label_title">Sembunyikan label tombol tindakan</string>
|
||||||
<string name="revanced_hide_action_button_label_summary">Menyembunyikan bilah dari tombol tindakan.</string>
|
<string name="revanced_hide_action_button_label_summary">Menyembunyikan label tombol tindakan.</string>
|
||||||
<string name="revanced_external_downloader_action_title">Ganti tombol tindakan Unduh</string>
|
<string name="revanced_external_downloader_action_title">Ganti tombol tindakan Unduh</string>
|
||||||
<string name="revanced_external_downloader_action_summary">"Tombol Unduh membuka Downloader eksternal kamu.
|
<string name="revanced_external_downloader_action_summary">"Tombol Unduh membuka pengunduh eksternal Anda
|
||||||
|
|
||||||
• Hanya menggantikan tombol Unduh di player.
|
• Hanya mengganti tombol tindakan Unduh di pemutar.
|
||||||
• Tidak bisa menggantikan tombol Unduh di menu flyout atau tab Library."</string>
|
• Tidak mengganti tombol Unduh di menu flyout atau tab Pustaka."</string>
|
||||||
<string name="revanced_external_downloader_package_name_title">Nama paket downloader eksternal</string>
|
<string name="revanced_external_downloader_package_name_title">Nama paket pengunduh eksternal</string>
|
||||||
<string name="revanced_external_downloader_package_name_summary">Nama paket aplikasi downloader eksternal yang terinstal, seperti NewPipe atau YTDLnis.</string>
|
<string name="revanced_external_downloader_package_name_summary">Nama paket aplikasi pengunduh eksternal yang terpasang, seperti NewPipe atau YTDLnis.</string>
|
||||||
<string name="revanced_external_downloader_dialog_title">Downloader eksternal</string>
|
<string name="revanced_external_downloader_dialog_title">Pengunduh eksternal</string>
|
||||||
<string name="revanced_external_downloader_not_installed_dialog_title">Peringatan</string>
|
<string name="revanced_external_downloader_not_installed_dialog_title">Peringatan</string>
|
||||||
<string name="revanced_external_downloader_not_installed_dialog_message">"%1$s belum terinstall.
|
<string name="revanced_external_downloader_not_installed_dialog_message">"%1$s belum terpasang.
|
||||||
Download %2$s dari website."</string>
|
Harap unduh %2$s dari website."</string>
|
||||||
<string name="revanced_external_downloader_not_installed_warning">%s tidak diinstal. Silakan instal.</string>
|
<string name="revanced_external_downloader_not_installed_warning">%s tidak dipasang. Silakan pasang terlebih dahulu.</string>
|
||||||
<!-- PreferenceScreen: Ads -->
|
<!-- PreferenceScreen: Ads -->
|
||||||
<string name="revanced_preference_screen_ads_title">Iklan</string>
|
<string name="revanced_preference_screen_ads_title">Iklan</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_title">Sembunyikan iklan fullscreen</string>
|
<string name="revanced_hide_fullscreen_ads_title">Sembunyikan iklan layar penuh</string>
|
||||||
|
<string name="revanced_hide_fullscreen_ads_summary">"Menyembunyikan iklan layar penuh.
|
||||||
|
|
||||||
|
Keterbatasan:
|
||||||
|
• Terkadang Anda mungkin melihat layar hitam kosong, bukan feed beranda."</string>
|
||||||
<string name="revanced_fullscreen_ads_closed_toast">Iklan layar penuh ditutup.</string>
|
<string name="revanced_fullscreen_ads_closed_toast">Iklan layar penuh ditutup.</string>
|
||||||
<string name="revanced_hide_general_ads_title">Sembunyikan Iklan Umum</string>
|
<string name="revanced_hide_general_ads_title">Sembunyikan Iklan Umum</string>
|
||||||
<string name="revanced_hide_general_ads_summary">Menyembunyikan Iklan Umum.</string>
|
<string name="revanced_hide_general_ads_summary">Menyembunyikan Iklan Umum.</string>
|
||||||
<string name="revanced_hide_music_ads_title">Sembunyikan iklan musik</string>
|
<string name="revanced_hide_music_ads_title">Sembunyikan iklan media</string>
|
||||||
<string name="revanced_hide_music_ads_summary">Menyembunyikan iklan sebelum memutar musik.</string>
|
<string name="revanced_hide_music_ads_summary">Menyembunyikan iklan sebelum memutar musik.</string>
|
||||||
<string name="revanced_hide_paid_promotion_label_title">Sembunyikan label promosi berbayar</string>
|
<string name="revanced_hide_paid_promotion_label_title">Sembunyikan label promosi berbayar</string>
|
||||||
<string name="revanced_hide_paid_promotion_label_summary">Menyembunyikan label promosi berbayar.</string>
|
<string name="revanced_hide_paid_promotion_label_summary">Menyembunyikan label promosi berbayar.</string>
|
||||||
@ -67,289 +71,411 @@ Download %2$s dari website."</string>
|
|||||||
<string name="revanced_hide_premium_renewal_title">Sembunyikan banner pembaruan premium</string>
|
<string name="revanced_hide_premium_renewal_title">Sembunyikan banner pembaruan premium</string>
|
||||||
<string name="revanced_hide_premium_renewal_summary">Menyembunyikan banner pembaruan premium.</string>
|
<string name="revanced_hide_premium_renewal_summary">Menyembunyikan banner pembaruan premium.</string>
|
||||||
<string name="revanced_hide_promotion_alert_banner_title">Sembunyikan banner peringatan promosi</string>
|
<string name="revanced_hide_promotion_alert_banner_title">Sembunyikan banner peringatan promosi</string>
|
||||||
|
<string name="revanced_hide_promotion_alert_banner_summary">Sembunyikan banner peringatan promosi.</string>
|
||||||
<!-- PreferenceScreen: Flyout menu -->
|
<!-- PreferenceScreen: Flyout menu -->
|
||||||
<string name="revanced_preference_screen_flyout_title">Menu flyout</string>
|
<string name="revanced_preference_screen_flyout_title">Menu flyout</string>
|
||||||
<string name="revanced_enable_trim_silence_title">Tambah switch Trim silence</string>
|
<string name="revanced_enable_trim_silence_title">Tambah tombol Pangkas keheningan</string>
|
||||||
<string name="revanced_enable_trim_silence_summary">"Menambahkan tombol Trim silence ke menu flyout playback speed.
|
<string name="revanced_enable_trim_silence_summary">"Menambahkan tombol Pangkas keheningan ke menu flyout kecepatan pemutaran.
|
||||||
|
|
||||||
Info:
|
Info:
|
||||||
• Fitur ini hanya untuk podcast.
|
• Fitur ini hanya untuk podcast.
|
||||||
• Fitur ini masih dalam pengembangan, jadi ini tidak akan stabil."</string>
|
• Fitur ini masih dalam pengembangan, jadi mungkin tidak stabil."</string>
|
||||||
<string name="revanced_enable_compact_dialog_title">Aktifkan dialog ringkas</string>
|
<string name="revanced_enable_compact_dialog_title">Aktifkan dialog ringkas</string>
|
||||||
<string name="revanced_enable_compact_dialog_summary">"Aktifkan dialog ringkas di ponsel.
|
<string name="revanced_enable_compact_dialog_summary">"Mengaktifkan dialog ringkas di ponsel.
|
||||||
|
|
||||||
Masalah yang diketahui:
|
Keterbatasan:
|
||||||
• Gambar album di Tab library juga menjadi lebih kecil.
|
• Gambar album di tab Pustaka juga menjadi lebih kecil ketika diatur dalam model kotak.
|
||||||
• Tata letak pengatur waktu tidur mungkin terlihat tidak biasa."</string>
|
• Tata letak pengatur waktu tidur mungkin terlihat tidak biasa."</string>
|
||||||
<string name="revanced_hide_flyout_menu_like_dislike_title">Sembunyikan tombol Like dan Dislike</string>
|
<string name="revanced_hide_flyout_menu_like_dislike_title">Sembunyikan tombol Suka dan Tidak suka</string>
|
||||||
<string name="revanced_hide_flyout_menu_3_column_component_title">Sembunyikan komponen 3-kolom</string>
|
<string name="revanced_hide_flyout_menu_3_column_component_title">Sembunyikan komponen 3-kolom</string>
|
||||||
<string name="revanced_hide_flyout_menu_add_to_queue_title">Sembunyikan menu tambahkan ke antrean</string>
|
<string name="revanced_hide_flyout_menu_add_to_queue_title">Sembunyikan menu tambahkan ke antrean</string>
|
||||||
<string name="revanced_hide_flyout_menu_captions_title">Sembunyikan menu teks</string>
|
<string name="revanced_hide_flyout_menu_captions_title">Sembunyikan menu Teks</string>
|
||||||
<string name="revanced_hide_flyout_menu_delete_playlist_title">Sembunyikan menu hapus playlist</string>
|
<string name="revanced_hide_flyout_menu_delete_playlist_title">Sembunyikan menu Hapus playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_dismiss_queue_title">Sembunyikan menu abaikan antrean</string>
|
<string name="revanced_hide_flyout_menu_dismiss_queue_title">Sembunyikan menu Abaikan antrean</string>
|
||||||
<string name="revanced_hide_flyout_menu_download_title">Sembunyikan menu Unduh</string>
|
<string name="revanced_hide_flyout_menu_download_title">Sembunyikan menu Unduh</string>
|
||||||
<string name="revanced_hide_flyout_menu_edit_playlist_title">Sembunyikan menu edit playlist</string>
|
<string name="revanced_hide_flyout_menu_edit_playlist_title">Sembunyikan menu Edit playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_album_title">Sembunyikan menu Pergi ke album</string>
|
<string name="revanced_hide_flyout_menu_go_to_album_title">Sembunyikan menu Pergi ke album</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_artist_title">Sembunyikan menu Pergi ke artis</string>
|
<string name="revanced_hide_flyout_menu_go_to_artist_title">Sembunyikan menu Pergi ke artis</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_episode_title">Sembunyikan menu Pergi ke episode</string>
|
<string name="revanced_hide_flyout_menu_go_to_episode_title">Sembunyikan menu Pergi ke episode</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_podcast_title">Sembunyikan menu Pergi ke podcast</string>
|
<string name="revanced_hide_flyout_menu_go_to_podcast_title">Sembunyikan menu Pergi ke podcast</string>
|
||||||
<string name="revanced_hide_flyout_menu_help_title">Sembunyikan menu bantuan & saran</string>
|
<string name="revanced_hide_flyout_menu_help_title">Sembunyikan menu Bantuan & saran</string>
|
||||||
<string name="revanced_hide_flyout_menu_play_next_title">Sembunyikan menu putar berikutnya</string>
|
<string name="revanced_hide_flyout_menu_not_interested_title">Sembunyikan menu Tidak tertarik</string>
|
||||||
<string name="revanced_hide_flyout_menu_quality_title">Hide menu Kualitas</string>
|
<string name="revanced_hide_flyout_menu_pin_to_speed_dial_title">Sembunyikan Pin ke menu Panggil cepat</string>
|
||||||
<string name="revanced_hide_flyout_menu_remove_from_library_title">Sembunyikan menu hapus dari koleksi</string>
|
<string name="revanced_hide_flyout_menu_play_next_title">Sembunyikan menu Putar berikutnya</string>
|
||||||
<string name="revanced_hide_flyout_menu_remove_from_playlist_title">Sembunyikan hapus dari menu playlist</string>
|
<string name="revanced_hide_flyout_menu_quality_title">Sembunyikan menu Kualitas</string>
|
||||||
<string name="revanced_hide_flyout_menu_report_title">Sembunyikan menu laporkan</string>
|
<string name="revanced_hide_flyout_menu_remove_from_library_title">Sembunyikan menu Hapus dari koleksi</string>
|
||||||
<string name="revanced_hide_flyout_menu_save_episode_for_later_title">Sembunyikan menu simpan episode untuk ditonton nanti</string>
|
<string name="revanced_hide_flyout_menu_remove_from_playlist_title">Sembunyikan menu Hapus dari playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_save_to_library_title">Sembunyikan menu simpan ke koleksi</string>
|
<string name="revanced_hide_flyout_menu_report_title">Sembunyikan menu Laporkan</string>
|
||||||
<string name="revanced_hide_flyout_menu_save_to_playlist_title">Sembunyikan menu simpan ke playlist</string>
|
<string name="revanced_hide_flyout_menu_save_episode_for_later_title">Sembunyikan menu Simpan episode untuk nanti</string>
|
||||||
<string name="revanced_hide_flyout_menu_share_title">Sembunyikan menu bagikan</string>
|
<string name="revanced_hide_flyout_menu_save_to_library_title">Sembunyikan menu Simpan ke pustaka</string>
|
||||||
<string name="revanced_hide_flyout_menu_shuffle_play_title">Sembunyikan menu putar acak</string>
|
<string name="revanced_hide_flyout_menu_save_to_playlist_title">Sembunyikan menu Simpan ke playlist</string>
|
||||||
<string name="revanced_hide_flyout_menu_sleep_timer_title">Sembunyikan menu waktu tidur</string>
|
<string name="revanced_hide_flyout_menu_share_title">Sembunyikan menu Bagikan</string>
|
||||||
<string name="revanced_hide_flyout_menu_start_radio_title">Sembunyikan menu mulai radio</string>
|
<string name="revanced_hide_flyout_menu_shuffle_play_title">Sembunyikan menu Putar acak</string>
|
||||||
<string name="revanced_hide_flyout_menu_stats_for_nerds_title">Sembunyikan menu statistik untuk nerds</string>
|
<string name="revanced_hide_flyout_menu_sleep_timer_title">Sembunyikan menu Waktu tidur</string>
|
||||||
<string name="revanced_hide_flyout_menu_subscribe_title">Sembunyikan menu Subscribe / Unsubscribe</string>
|
<string name="revanced_hide_flyout_menu_start_radio_title">Sembunyikan menu Mulai radio</string>
|
||||||
<string name="revanced_hide_flyout_menu_view_song_credit_title">Sembunyikan menu kredit lagu</string>
|
<string name="revanced_hide_flyout_menu_stats_for_nerds_title">Sembunyikan menu Statistik untuk nerds</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_subscribe_title">Sembunyikan menu Berlangganan / Berhenti Berlangganan</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_unpin_from_speed_dial_title">Sembunyikan Buka pin dari menu panggilan cepat</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_view_song_credit_title">Sembunyikan menu Lihat kredit lagu</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_title">Lanjutkan menonton</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_title">Lanjutkan menonton</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_summary">Melanjutkan video dari waktu saat ini ketika berlaih ke YouTube.</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_continue_watch_summary">Melanjutkan video dari waktu saat ini ketika beralih ke YouTube.</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_label">Tonton di YouTube</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_label">Tonton di YouTube</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_warning">Url video tidak valid.</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_watch_on_youtube_warning">Url video tidak sah.</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_title">Ganti menu hapus antrean</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_title">Ganti menu Hapus antrean</string>
|
||||||
<string name="revanced_replace_flyout_menu_dismiss_queue_summary">Menggantikan menu hapus antrean menjadi tonton di YouTube.</string>
|
<string name="revanced_replace_flyout_menu_dismiss_queue_summary">Menggantikan menu Hapus antrean dengan menu Tonton di YouTube.</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_title">Ganti menu laporkan</string>
|
<string name="revanced_replace_flyout_menu_report_title">Ganti menu Laporkan</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_summary">Menggantikan menu laporkan dengan menu Kecepatan pemutaran.</string>
|
<string name="revanced_replace_flyout_menu_report_summary">Menggantikan menu Laporkan dengan menu Kecepatan pemutaran.</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_only_player_title">Simpan laporkan di komentar</string>
|
<string name="revanced_replace_flyout_menu_report_only_player_title">Simpan Laporkan di komentar</string>
|
||||||
<string name="revanced_replace_flyout_menu_report_only_player_summary">Mempertahankan menu laporkan di bagian komentar.</string>
|
<string name="revanced_replace_flyout_menu_report_only_player_summary">Menyimpan menu Laporkan di bagian komentar tetap utuh.</string>
|
||||||
<!-- PreferenceScreen: General -->
|
<!-- PreferenceScreen: General -->
|
||||||
<string name="revanced_preference_screen_general_title">Umum</string>
|
<string name="revanced_preference_screen_general_title">Umum</string>
|
||||||
<string name="revanced_change_start_page_title">Ganti Halaman Awal</string>
|
<string name="revanced_change_start_page_title">Ganti Halaman Awal</string>
|
||||||
<string name="revanced_change_start_page_summary">Select which page the app opens in.</string>
|
<string name="revanced_change_start_page_summary">Pilih di halaman mana aplikasi dibuka.</string>
|
||||||
|
<string name="revanced_change_start_page_entry_default">Bawaan</string>
|
||||||
|
<string name="revanced_change_start_page_entry_charts">Tangga lagu</string>
|
||||||
|
<string name="revanced_change_start_page_entry_episodes_for_later">Episode untuk Nanti</string>
|
||||||
<string name="revanced_change_start_page_entry_explore">Jelajahi</string>
|
<string name="revanced_change_start_page_entry_explore">Jelajahi</string>
|
||||||
<string name="revanced_change_start_page_entry_library">Koleksi</string>
|
<string name="revanced_change_start_page_entry_history">Riwayat</string>
|
||||||
<string name="revanced_disable_dislike_redirection_title">Disable dislike redirection</string>
|
<string name="revanced_change_start_page_entry_library">Pustaka</string>
|
||||||
<string name="revanced_disable_dislike_redirection_summary">Disables redirection to the next track when clicking the Dislike button.</string>
|
<string name="revanced_change_start_page_entry_liked_music">Musik yang Disukai</string>
|
||||||
|
<string name="revanced_change_start_page_entry_podcasts">Podcast</string>
|
||||||
|
<string name="revanced_change_start_page_entry_samples">Sampel</string>
|
||||||
|
<string name="revanced_change_start_page_entry_search">Cari</string>
|
||||||
|
<string name="revanced_change_start_page_entry_subscriptions">Berlangganan</string>
|
||||||
|
<string name="revanced_disable_dislike_redirection_title">Nonaktifkan pengalihan tidak suka</string>
|
||||||
|
<string name="revanced_disable_dislike_redirection_summary">Menonaktifkan pengalihan ke trek berikutnya ketika mengklik tombol Tidak Suka.</string>
|
||||||
<string name="revanced_disable_auto_captions_title">Nonaktifkan teks otomatis paksa</string>
|
<string name="revanced_disable_auto_captions_title">Nonaktifkan teks otomatis paksa</string>
|
||||||
<string name="revanced_disable_auto_captions_summary">Teks otomatis paksa yang dinonaktifkan.</string>
|
<string name="revanced_disable_auto_captions_summary">Menonaktifkan teks otomatis agar tidak aktif.</string>
|
||||||
<string name="revanced_enable_landscape_mode_title">Aktifkan mode lanskap</string>
|
<string name="revanced_enable_landscape_mode_title">Aktifkan mode lanskap</string>
|
||||||
<string name="revanced_enable_landscape_mode_summary">Mengaktifkan masuk ke mode lanskap dengan rotasi layar di ponsel.</string>
|
<string name="revanced_enable_landscape_mode_summary">Mengaktifkan mode lanskap saat memutar layar ponsel.</string>
|
||||||
<string name="revanced_custom_filter_title">Aktifkan filter kustom</string>
|
<string name="revanced_custom_filter_title">Aktifkan filter khusus</string>
|
||||||
<string name="revanced_custom_filter_summary">Mengaktifkan filter kustom untuk menyembunyikan komponen tata letak.</string>
|
<string name="revanced_custom_filter_summary">Mengaktifkan filter kustom untuk menyembunyikan komponen tata letak.</string>
|
||||||
<string name="revanced_custom_filter_strings_title">Edit filter kustom</string>
|
<string name="revanced_custom_filter_strings_title">Edit filter khusus</string>
|
||||||
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
|
<!-- 'Component path builder strings' is the technical name for identifying the Litho UI layout items to hide. This is an advanced feature and most users will never use this. -->
|
||||||
<string name="revanced_custom_filter_strings_summary">Memfilter nama komponen dengan baris yang dipisahkan.</string>
|
<string name="revanced_custom_filter_strings_summary">Daftar string pembangun jalur komponen yang akan disaring, dipisahkan dengan baris baru.</string>
|
||||||
<string name="revanced_custom_filter_toast_invalid_syntax">Invalid custom filter: %s.</string>
|
<string name="revanced_custom_filter_toast_invalid_syntax">Filter khusus tidak sah: %s.</string>
|
||||||
<string name="revanced_hide_button_shelf_title">Sembunyikan rak tombol</string>
|
<string name="revanced_hide_button_shelf_title">Sembunyikan rak tombol</string>
|
||||||
<string name="revanced_hide_button_shelf_summary">Menyembunyikan rak tombol dari beranda dan eksplorasi.</string>
|
<string name="revanced_hide_button_shelf_summary">Menyembunyikan rak tombol di feed.</string>
|
||||||
<string name="revanced_hide_carousel_shelf_title">Sembunyikan rak korsel</string>
|
<string name="revanced_hide_carousel_shelf_title">Menyembunyikan rak carousel</string>
|
||||||
<string name="revanced_hide_carousel_shelf_summary">Menyembunyikan rak korsel dari beranda dan eksplorasi.</string>
|
<string name="revanced_hide_carousel_shelf_summary">Menyembunyikan rak carousel di feed.</string>
|
||||||
<string name="revanced_hide_cast_button_title">Sembunyikan tombol cast</string>
|
<string name="revanced_hide_cast_button_title">Sembunyikan tombol Cast</string>
|
||||||
<string name="revanced_hide_cast_button_summary">Menyembunyikan tombol cast.</string>
|
<string name="revanced_hide_cast_button_summary">Menyembunyikan tombol Cast.</string>
|
||||||
<string name="revanced_hide_category_bar_title">Sembunyikan bilah kategori</string>
|
<string name="revanced_hide_category_bar_title">Sembunyikan bilah kategori</string>
|
||||||
<string name="revanced_hide_category_bar_summary">Menyembunyikan bilah kategori musik di bagian atas beranda.</string>
|
<string name="revanced_hide_category_bar_summary">Menyembunyikan bilah kategori.</string>
|
||||||
<string name="revanced_hide_floating_button_title">Hide floating button</string>
|
<string name="revanced_hide_floating_button_title">Sembunyikan tombol mengambang</string>
|
||||||
<string name="revanced_hide_floating_button_summary">Hides the floating button in the Library tab.</string>
|
<string name="revanced_hide_floating_button_summary">Menyembunyikan tombol mengambang di tab Pustaka.</string>
|
||||||
<string name="revanced_hide_history_button_title">Sembunyikan tombol riwayat</string>
|
<string name="revanced_hide_history_button_title">Sembunyikan tombol Riwayat</string>
|
||||||
<string name="revanced_hide_history_button_summary">Menyembunyikan tombol riwayat di toolbar.</string>
|
<string name="revanced_hide_history_button_summary">Menyembunyikan Rombol riwayat di toolbar.</string>
|
||||||
<string name="revanced_hide_notification_button_title">Hide Notifications button</string>
|
<string name="revanced_hide_notification_button_title">Sembunyikan tombol Pemberitahuan</string>
|
||||||
<string name="revanced_hide_notification_button_summary">Hides the Notifications button in the toolbar.</string>
|
<string name="revanced_hide_notification_button_summary">Menyembunyikan tombol Pemberitahuan di toolbar.</string>
|
||||||
<string name="revanced_hide_playlist_card_shelf_title">Hide playlist card shelf</string>
|
<string name="revanced_hide_playlist_card_shelf_title">Sembunyikan rak kartu playlist</string>
|
||||||
<string name="revanced_hide_playlist_card_shelf_summary">Hides the playlist card shelf in the feed.</string>
|
<string name="revanced_hide_playlist_card_shelf_summary">Menyembunyikan rak kartu playlist di feed.</string>
|
||||||
<string name="revanced_hide_samples_shelf_title">Hide Samples shelf</string>
|
<string name="revanced_hide_samples_shelf_title">Sembunyikan rak Sampel</string>
|
||||||
<string name="revanced_hide_samples_shelf_summary">Hides the Samples shelf in the feed.</string>
|
<string name="revanced_hide_samples_shelf_summary">Menyembunyikan rak Sampel di feed.</string>
|
||||||
<string name="revanced_hide_sound_search_button_title">Hide sound search button</string>
|
<string name="revanced_hide_sound_search_button_title">Sembunyikan tombol pencarian suara</string>
|
||||||
<string name="revanced_hide_sound_search_button_summary">Hides the sound search button in the search bar.</string>
|
<string name="revanced_hide_sound_search_button_summary">Menyembunyikan tombol pencarian suara di bilah pencarian.</string>
|
||||||
<string name="revanced_hide_tap_to_update_button_title">Hide \'Tap to update\' button</string>
|
<string name="revanced_hide_tap_to_update_button_title">Sembunyikan tombol Ketuk untuk memperbarui</string>
|
||||||
<string name="revanced_hide_tap_to_update_button_summary">Hides the \'Tap to update\' button.</string>
|
<string name="revanced_hide_tap_to_update_button_summary">Menyembunyikan tombol Ketuk untuk memperbarui.</string>
|
||||||
<string name="revanced_hide_voice_search_button_title">Hide voice search button</string>
|
<string name="revanced_hide_voice_search_button_title">Sembunyikan tombol pencarian suara</string>
|
||||||
<string name="revanced_hide_voice_search_button_summary">Hides the voice search button in the search bar.</string>
|
<string name="revanced_hide_voice_search_button_summary">Menyembunyikan tombol pencarian suara di bilah pencarian.</string>
|
||||||
<string name="revanced_restore_old_style_library_shelf_title">Restore old style library shelf</string>
|
<string name="revanced_restore_old_style_library_shelf_title">Pulihkan tab Pustaka lama</string>
|
||||||
<string name="revanced_restore_old_style_library_shelf_summary">Returns the Library tab to the old style. (Experimental)</string>
|
<string name="revanced_restore_old_style_library_shelf_summary">Memulihkan tab Pustaka ke gaya lama. (Eksperimental)</string>
|
||||||
<string name="revanced_remove_viewer_discretion_dialog_title">Remove viewer discretion dialog</string>
|
<string name="revanced_remove_viewer_discretion_dialog_title">Hapus dialog pembatasan penonton</string>
|
||||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"Removes the viewer discretion dialog.
|
<string name="revanced_remove_viewer_discretion_dialog_summary">"Menghapus dialog pembatasan penonton.
|
||||||
This does not bypass the age restriction. It just accepts it automatically."</string>
|
Ini tidak mengabaikan pembatasan usia. Ini hanya menerimanya secara otomatis."</string>
|
||||||
<string name="revanced_spoof_app_version_title">Palsukan versi aplikasi</string>
|
<string name="revanced_spoof_app_version_title">Palsukan versi aplikasi</string>
|
||||||
<string name="revanced_spoof_app_version_summary">"Memalsukan versi klien ke versi lama
|
<string name="revanced_spoof_app_version_summary">"Memalsukan versi klien ke versi lama.
|
||||||
|
|
||||||
• Ini akan mengubah tampilan aplikasi, namun efek samping yang tidak diketahui mungkin terjadi.
|
• Ini akan mengubah tampilan aplikasi, namun efek samping yang tidak diketahui mungkin terjadi.
|
||||||
• Jika nanti dinonaktifkan, UI lama mungkin tetap ada hingga aplikasi dihapus data."</string>
|
• Jika nanti dinonaktifkan, UI lama mungkin tetap ada hingga data aplikasi dihapus."</string>
|
||||||
<string name="revanced_spoof_app_version_target_title">Target pemalsuan versi aplikasi</string>
|
<string name="revanced_spoof_app_version_target_title">Target pemalsuan versi aplikasi</string>
|
||||||
<string name="revanced_spoof_app_version_target_summary">Pilih target pemalsuan versi aplikasi.</string>
|
<string name="revanced_spoof_app_version_target_summary">Pilih target pemalsuan versi aplikasi.</string>
|
||||||
<string name="revanced_spoof_app_version_target_entry_6_42_55"></string>
|
<string name="revanced_spoof_app_version_target_entry_6_42_55">6.42.55 - Nonaktifkan lirik real-time</string>
|
||||||
|
<string name="revanced_spoof_app_version_target_entry_7_16_53">7.16.53 - Pulihkan bilah tindakan lama</string>
|
||||||
<!-- PreferenceScreen: Navigation bar -->
|
<!-- PreferenceScreen: Navigation bar -->
|
||||||
<string name="revanced_preference_screen_navigation_title">Bilah Navigasi</string>
|
<string name="revanced_preference_screen_navigation_title">Bilah Navigasi</string>
|
||||||
<string name="revanced_hide_navigation_home_button_title">Hide Home button</string>
|
<string name="revanced_enable_custom_navigation_bar_color_title">Aktifkan warna bilah navigasi khusus</string>
|
||||||
<string name="revanced_hide_navigation_home_button_summary">Hides the Home button.</string>
|
<string name="revanced_enable_custom_navigation_bar_color_summary">Atur warna bilah navigasi.</string>
|
||||||
<string name="revanced_hide_navigation_samples_button_title">Hide Samples button</string>
|
<string name="revanced_custom_navigation_bar_color_value_title">Nilai warna bilah navigasi khusus</string>
|
||||||
<string name="revanced_hide_navigation_samples_button_summary">Hides the Samples button.</string>
|
<string name="revanced_custom_navigation_bar_color_value_summary">Masukkan kode hex dari warna bilah navigasi.</string>
|
||||||
<string name="revanced_hide_navigation_explore_button_title">Hide Explore button</string>
|
<string name="revanced_custom_navigation_bar_color_value_invalid_invalid_toast">Nilai warna bilah navigasi tidak sah.</string>
|
||||||
<string name="revanced_hide_navigation_explore_button_summary">Hides the Explore button.</string>
|
<string name="revanced_hide_navigation_home_button_title">Sembunyikan tombol Beranda</string>
|
||||||
<string name="revanced_hide_navigation_library_button_title">Hide Library button</string>
|
<string name="revanced_hide_navigation_home_button_summary">Menyembunyikan tombol Beranda.</string>
|
||||||
<string name="revanced_hide_navigation_library_button_summary">Hides the Library button.</string>
|
<string name="revanced_hide_navigation_samples_button_title">Sembunyikan tombol Sampel</string>
|
||||||
<string name="revanced_hide_navigation_upgrade_button_title">Hide Upgrade button</string>
|
<string name="revanced_hide_navigation_samples_button_summary">Menyembunyikan tombol Sampel.</string>
|
||||||
<string name="revanced_hide_navigation_upgrade_button_summary">Hides the Upgrade button.</string>
|
<string name="revanced_hide_navigation_explore_button_title">Sembunyikan tombol Jelajahi</string>
|
||||||
<string name="revanced_hide_navigation_bar_title">Menyembunyikan bilah navigasi</string>
|
<string name="revanced_hide_navigation_explore_button_summary">Menyembunyikan tombol Jelajahi.</string>
|
||||||
<string name="revanced_hide_navigation_bar_summary">Sembunyikan bilah navigasi.</string>
|
<string name="revanced_hide_navigation_library_button_title">Sembunyikan tombol Pustaka</string>
|
||||||
|
<string name="revanced_hide_navigation_library_button_summary">Menyembunyikan tombol Pustaka.</string>
|
||||||
|
<string name="revanced_hide_navigation_upgrade_button_title">Sembunyikan tombol Upgrade</string>
|
||||||
|
<string name="revanced_hide_navigation_upgrade_button_summary">Menyembunyikan tombol Upgrade.</string>
|
||||||
|
<string name="revanced_hide_navigation_bar_title">Sembunyikan bilah navigasi</string>
|
||||||
|
<string name="revanced_hide_navigation_bar_summary">Menyembunyikan bilah navigasi.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Sembunyikan label navigasi</string>
|
<string name="revanced_hide_navigation_label_title">Sembunyikan label navigasi</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Menyembunyikan label di bilah navigasi.</string>
|
<string name="revanced_hide_navigation_label_summary">Menyembunyikan label di bawah setiap tombol navigasi.</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Player</string>
|
<string name="revanced_preference_screen_player_title">Pemutar</string>
|
||||||
<string name="revanced_disable_player_gesture_title">Menonaktifkan gerakan pemutar</string>
|
<string name="revanced_add_miniplayer_next_button_title">Menambahkan tombol berikutnya pemutar mini</string>
|
||||||
<string name="revanced_disable_player_gesture_summary">Nonaktifkan usap untuk mengubah trek di pemutar.</string>
|
<string name="revanced_add_miniplayer_next_button_summary">Menambahkan tombol trek berikutnya ke pemutar mini.</string>
|
||||||
<string name="revanced_enable_zen_mode_title">Aktifkan mode zen</string>
|
<string name="revanced_add_miniplayer_previous_button_title">Tambahkan tombol sebelumnya miniplayer</string>
|
||||||
<string name="revanced_enable_zen_mode_summary">Menambahkan rona abu-abu ke pemutar video untuk mengurangi ketegangan mata.</string>
|
<string name="revanced_add_miniplayer_previous_button_summary">Menambahkan tombol trek sebelumnya ke pemutar mini.</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_title">Enable Zen mode in podcasts</string>
|
<string name="revanced_change_miniplayer_color_title">Ubah warna pemutar mini</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_summary">Also enables Zen mode for podcasts.</string>
|
<string name="revanced_change_miniplayer_color_summary">Mengubah warna pemutar mini supaya sesuai dengan pemutar layar penuh.</string>
|
||||||
<string name="revanced_hide_comment_channel_guidelines_title">Hide channel guidelines</string>
|
<string name="revanced_change_player_background_color_title">Ubah warna latar belakang pemutar</string>
|
||||||
<string name="revanced_hide_comment_channel_guidelines_summary">Hides the channel guidelines at the top of the comments section.</string>
|
<string name="revanced_change_player_background_color_summary">Mengubah warna latar belakang pemutar ke warna khusus.</string>
|
||||||
<string name="revanced_hide_double_tap_overlay_filter_title">Sembunyikan filter overlay double-tap</string>
|
<string name="revanced_custom_player_background_color_primary_title">Warna primer latar belakang pemutar</string>
|
||||||
<string name="revanced_hide_double_tap_overlay_filter_summary">Menyembunyikan overlay gelap yang muncul ketika double-tap to seek.</string>
|
<string name="revanced_custom_player_background_color_primary_summary">"Masukkan kode hex dari warna primer latar belakang pemutar.
|
||||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_title">Hide timestamp and emoji buttons</string>
|
|
||||||
|
Gunakan warna gelap jika memungkinkan, karena aplikasi ini tidak mendukung tema terang."</string>
|
||||||
|
<string name="revanced_custom_player_background_color_secondary_title">Warna sekunder latar belakang pemutar</string>
|
||||||
|
<string name="revanced_custom_player_background_color_secondary_summary">"Masukkan kode hex warna sekunder latar belakang pemutar.
|
||||||
|
|
||||||
|
Gunakan warna gelap jika memungkinkan, karena aplikasi ini tidak mendukung tema terang."</string>
|
||||||
|
<string name="revanced_custom_player_background_invalid_toast">Warna latar belakang pemutar tidak sah.</string>
|
||||||
|
<string name="revanced_change_seekbar_position_title">Ubah posisi seekbar</string>
|
||||||
|
<string name="revanced_change_seekbar_position_summary">Memindahkan seekbar di bawah tombol putar.</string>
|
||||||
|
<string name="revanced_disable_miniplayer_gesture_title">Nonaktifkan gerakan pemutar mini</string>
|
||||||
|
<string name="revanced_disable_miniplayer_gesture_summary">Menonaktifkan usapan untuk mengubah trek di pemutar mini.</string>
|
||||||
|
<string name="revanced_disable_player_gesture_title">Nonaktifkan gerakan pemutar</string>
|
||||||
|
<string name="revanced_disable_player_gesture_summary">Menonaktifkan usap untuk mengubah trek di pemutar.</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_title">Aktifkan pemutar mini paksa</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_summary">Mengaktifkan pemutar mini paksa saat beralih ke trek baru.</string>
|
||||||
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">Aktifkan usapan untuk menutup pemutar mini</string>
|
||||||
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">Mengaktifkan gesek ke bawah untuk menutup pemutar mini.</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_title">Aktifkan seekbar tebal</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_summary">"Mengaktifkan seekbar yang tebal.
|
||||||
|
|
||||||
|
Keterbatasan: Segmen SponsorBlock tidak ditampilkan di seekbar."</string>
|
||||||
|
<string name="revanced_enable_zen_mode_title">Aktifkan mode Zen</string>
|
||||||
|
<string name="revanced_enable_zen_mode_summary">Mengaktifkan warna abu-abu muda untuk latar belakang pemutar untuk mengurangi kelelahan mata.</string>
|
||||||
|
<string name="revanced_enable_zen_mode_podcast_title">Aktifkan mode Zen di podcast</string>
|
||||||
|
<string name="revanced_enable_zen_mode_podcast_summary">Mengaktifkan mode Zen di podcast.</string>
|
||||||
|
<string name="revanced_hide_comment_channel_guidelines_title">Sembunyikan pedoman saluran</string>
|
||||||
|
<string name="revanced_hide_comment_channel_guidelines_summary">Menyembunyikan panduan saluran di bagian atas komentar.</string>
|
||||||
|
<string name="revanced_hide_double_tap_overlay_filter_title">Sembunyikan penyaring hamparan ketuk dua kali</string>
|
||||||
|
<string name="revanced_hide_double_tap_overlay_filter_summary">Menyembunyikan hamparan gelap yang muncul ketika mengetuk dua kali untuk menggeser.</string>
|
||||||
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_title">Sembunyikan tombol emoji dan stempel waktu</string>
|
||||||
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary">Hides the timestamp and emoji buttons when typing comments.</string>
|
<string name="revanced_hide_comment_timestamp_and_emoji_buttons_summary">Hides the timestamp and emoji buttons when typing comments.</string>
|
||||||
<string name="revanced_hide_fullscreen_share_button_title">Hide fullscreen Share button</string>
|
<string name="revanced_hide_fullscreen_share_button_title">Sembunyikan tombol Bagikan layar penuh</string>
|
||||||
<string name="revanced_hide_fullscreen_share_button_summary">Hides the Share button in the fullscreen player.</string>
|
<string name="revanced_hide_fullscreen_share_button_summary">Menyembunyikan tombol Bagikan di pemutar layar penuh.</string>
|
||||||
|
<string name="revanced_hide_song_video_toggle_title">Sembunyikan tombol Lagu / Video</string>
|
||||||
|
<string name="revanced_hide_song_video_toggle_summary">Menyembunyikan tombol Lagu / Video di pemutar.</string>
|
||||||
<string name="revanced_remember_repeat_state_title">Ingat keadaan pengulangan</string>
|
<string name="revanced_remember_repeat_state_title">Ingat keadaan pengulangan</string>
|
||||||
<string name="revanced_remember_repeat_state_summary">Mengingat keadaan pengulangan.</string>
|
<string name="revanced_remember_repeat_state_summary">Mengingat keadaan tombol pengulangan.</string>
|
||||||
<string name="revanced_remember_shuffle_state_title">Ingat keadaan pengacakan</string>
|
<string name="revanced_remember_shuffle_state_title">Ingat keadaan pengacakan</string>
|
||||||
<string name="revanced_remember_shuffle_state_summary">Mengingat keadaan pengacakan.</string>
|
<string name="revanced_remember_shuffle_state_summary">Mengingat status tombol pengacakan.</string>
|
||||||
<string name="revanced_restore_old_comments_popup_panels_title">Restore old comments popup panels</string>
|
<string name="revanced_restore_old_comments_popup_panels_title">Pulihkan panel sembulan komentar lama</string>
|
||||||
<string name="revanced_restore_old_comments_popup_panels_summary">Returns the comments popup panels to the old style.</string>
|
<string name="revanced_restore_old_comments_popup_panels_summary">Memulihkan panel sembulan komentar ke gaya lama.</string>
|
||||||
<string name="revanced_restore_old_player_background_title">Restore old player background</string>
|
<string name="revanced_restore_old_player_background_title">Pulihkan latar belakang pemutar lama</string>
|
||||||
<string name="revanced_restore_old_player_background_summary">Returns the player background to the old style.</string>
|
<string name="revanced_restore_old_player_background_summary">Mengembalikan latar belakang pemutar ke gaya lama.</string>
|
||||||
<string name="revanced_restore_old_player_layout_title">Restore old player layout</string>
|
<string name="revanced_restore_old_player_layout_title">Pulihkan tata letak pemutar lama</string>
|
||||||
<string name="revanced_restore_old_player_layout_summary">"Returns the player layout to the old style.
|
<string name="revanced_restore_old_player_layout_summary">"Memulihkan tata letak pemutar ke gaya lama.
|
||||||
Some features may not work properly in the old player layout."</string>
|
Beberapa fitur mungkin tidak berfungsi dengan baik dalam tata letak pemutar lama."</string>
|
||||||
<!-- PreferenceScreen: Settings menu -->
|
<!-- PreferenceScreen: Settings menu -->
|
||||||
|
<string name="revanced_preference_screen_settings_title">Menu pengaturan</string>
|
||||||
|
<string name="revanced_hide_settings_menu_parent_tools_title">Sembunyikan menu Pusat Keluarga</string>
|
||||||
|
<string name="revanced_hide_settings_menu_general_title">Sembunyikan menu Umum</string>
|
||||||
|
<string name="revanced_hide_settings_menu_playback_title">Sembunyikan menu Pemutaran</string>
|
||||||
|
<string name="revanced_hide_settings_menu_data_saving_title">Sembunyikan menu penghematan Data</string>
|
||||||
|
<string name="revanced_hide_settings_menu_downloads_and_storage_title">Sembunyikan menu Unduhan & penyimpanan</string>
|
||||||
|
<string name="revanced_hide_settings_menu_notification_title">Sembunyikan menu Pemberitahuan</string>
|
||||||
|
<string name="revanced_hide_settings_menu_privacy_and_location_title">Sembunyikan menu Privasi & data</string>
|
||||||
|
<string name="revanced_hide_settings_menu_recommendations_title">Sembunyikan menu Rekomendasi</string>
|
||||||
|
<string name="revanced_hide_settings_menu_paid_memberships_title">Sembunyikan menu Dapatkan Music premium</string>
|
||||||
|
<string name="revanced_hide_settings_menu_about_title">Sembunyikan menu Tentang</string>
|
||||||
<!-- PreferenceScreen: Video -->
|
<!-- PreferenceScreen: Video -->
|
||||||
<string name="revanced_preference_screen_video_title">Video</string>
|
<string name="revanced_preference_screen_video_title">Video</string>
|
||||||
<string name="revanced_custom_playback_speeds_title">Edit kecepatan pemutaran kustom</string>
|
<string name="revanced_custom_playback_speeds_title">Edit kecepatan pemutaran khusus</string>
|
||||||
<string name="revanced_custom_playback_speeds_summary">Menambah atau mengubah kecepatan pemutaran yang tersedia.</string>
|
<string name="revanced_custom_playback_speeds_summary">Menambah atau mengubah kecepatan pemutaran yang tersedia.</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_title">Remember playback speed changes</string>
|
<string name="revanced_remember_playback_speed_last_selected_title">Ingat perubahan kecepatan pemutaran</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_summary">Remembers the last playback speed selected.</string>
|
<string name="revanced_remember_playback_speed_last_selected_summary">Remembers the last playback speed selected.</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_toast_title">Tampilkan toast</string>
|
<string name="revanced_remember_playback_speed_last_selected_toast_title">Tampilkan toast</string>
|
||||||
<string name="revanced_remember_playback_speed_last_selected_toast_summary">Menunjukkan toast ketika mengubah playback speed semula.</string>
|
<string name="revanced_remember_playback_speed_last_selected_toast_summary">Menampilkan toast saat mengubah kecepatan pemutaran bawaan.</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_title">Remember video quality changes</string>
|
<string name="revanced_remember_video_quality_last_selected_title">Ingat perubahan kualitas video</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_summary">Remembers the last video quality selected.</string>
|
<string name="revanced_remember_video_quality_last_selected_summary">Mengingat kualitas video terakhir yang dipilih.</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_toast_title">Tampilkan toast</string>
|
<string name="revanced_remember_video_quality_last_selected_toast_title">Tampilkan toast</string>
|
||||||
<string name="revanced_remember_video_quality_last_selected_toast_summary">Menunjukkan toast ketika mengubah playback speed semula.</string>
|
<string name="revanced_remember_video_quality_last_selected_toast_summary">Menampilkan toast ketika mengubah kualitas video bawaan.</string>
|
||||||
<string name="revanced_custom_playback_speeds_invalid">Kecepatan pemutaran kustom tidak valid. Atur ulang ke nilai default.</string>
|
<string name="revanced_custom_playback_speeds_invalid">Kecepatan khusus harus kurang dari %sx.</string>
|
||||||
<string name="revanced_custom_playback_speeds_parse_exception">Invalid custom playback speeds. Using default values.</string>
|
<string name="revanced_custom_playback_speeds_parse_exception">Kecepatan pemutaran kustom tidak sah.</string>
|
||||||
<string name="revanced_remember_playback_speed_toast">Changing default speed to %s.</string>
|
<string name="revanced_remember_playback_speed_toast">Mengubah kecepatan bawaan ke %s.</string>
|
||||||
<string name="revanced_remember_video_quality_mobile">Changing default mobile data quality to %s.</string>
|
<string name="revanced_remember_video_quality_mobile">Mengubah kualitas data seluler bawaan ke %s.</string>
|
||||||
<string name="revanced_remember_video_quality_none">Failed to set quality.</string>
|
<string name="revanced_remember_video_quality_none">Gagal mengatur kualitas.</string>
|
||||||
<string name="revanced_remember_video_quality_wifi">Changing default Wi-Fi quality to %s.</string>
|
<string name="revanced_remember_video_quality_wifi">Mengubah kualitas Wi-Fi bawaan ke %s.</string>
|
||||||
<!-- PreferenceScreen: Return YouTube Dislike -->
|
<!-- PreferenceScreen: Return YouTube Dislike -->
|
||||||
<string name="revanced_preference_screen_ryd_title">Return YouTube Dislike</string>
|
<string name="revanced_preference_screen_ryd_title">Return YouTube Dislike</string>
|
||||||
<string name="revanced_ryd_enabled_title">Enable Return YouTube Dislike</string>
|
<string name="revanced_ryd_enabled_title">Aktifkan Return YouTube Dislike</string>
|
||||||
<string name="revanced_ryd_enabled_summary">Menunjukkan jumlah dislike pada video.</string>
|
<string name="revanced_ryd_enabled_summary">Menampilkan jumlah tidak suka pada video.</string>
|
||||||
<string name="revanced_ryd_dislike_percentage_title">Dislike sebagai persentase</string>
|
<string name="revanced_ryd_dislike_percentage_title">Dislike sebagai persentase</string>
|
||||||
<string name="revanced_ryd_dislike_percentage_summary">Alih-alih jumlah dislike, yang ditampilkan adalah persentase dislike.</string>
|
<string name="revanced_ryd_dislike_percentage_summary">Menampilkan persentase dislike, bukan jumlah dislike.</string>
|
||||||
<string name="revanced_ryd_compact_layout_title">Tombol like ringkas</string>
|
<string name="revanced_ryd_compact_layout_title">Tombol suka ringkas</string>
|
||||||
<string name="revanced_ryd_compact_layout_summary">Menyembunyikan pemisah tombol like.</string>
|
<string name="revanced_ryd_compact_layout_summary">Menyembunyikan pemisah tombol suka.</string>
|
||||||
<string name="revanced_ryd_toast_on_connection_error_title">Show a toast if API is unavailable</string>
|
<string name="revanced_ryd_estimated_like_title">Tampilkan perkiraan suka</string>
|
||||||
<string name="revanced_ryd_toast_on_connection_error_summary">Shows a toast if the Return YouTube Dislike API is unavailable.</string>
|
<string name="revanced_ryd_estimated_like_summary">Menampilkan perkiraan jumlah suka video.</string>
|
||||||
|
<string name="revanced_ryd_toast_on_connection_error_title">Tampilkan toast jika API tidak tersedia</string>
|
||||||
|
<string name="revanced_ryd_toast_on_connection_error_summary">Menampilkan toast jika API Return YouTube Dislike tidak tersedia.</string>
|
||||||
<string name="revanced_ryd_about">Tentang</string>
|
<string name="revanced_ryd_about">Tentang</string>
|
||||||
<string name="revanced_ryd_attribution_title">ReturnYouTubeDislike.com</string>
|
<string name="revanced_ryd_attribution_title">ReturnYouTubeDislike.com</string>
|
||||||
<string name="revanced_ryd_attribution_summary">Data disediakan oleh API Return YouTube Dislike. Tekan di sini untuk mempelajari lebih lanjut.</string>
|
<string name="revanced_ryd_attribution_summary">Data disediakan oleh API Return YouTube Dislike. Tekan di sini untuk mempelajari lebih lanjut.</string>
|
||||||
<string name="revanced_ryd_failure_connection_timeout">Dislikes are temporarily unavailable (API timed out).</string>
|
<string name="revanced_ryd_failure_connection_timeout">Dislike untuk sementara tidak tersedia (API kehabisan waktu).</string>
|
||||||
<string name="revanced_ryd_failure_connection_status_code">Dislikes are unavailable (status %d).</string>
|
<string name="revanced_ryd_failure_connection_status_code">Dislike tidak tersedia (status %d).</string>
|
||||||
<string name="revanced_ryd_failure_client_rate_limit_requested">Dislike tidak tersedia (batas API client tercapai).</string>
|
<string name="revanced_ryd_failure_client_rate_limit_requested">Dislike tidak tersedia (batas API client tercapai).</string>
|
||||||
<string name="revanced_ryd_failure_generic">Dislikes are unavailable (%s).</string>
|
<string name="revanced_ryd_failure_generic">Dislikes tidak tersedia (%s).</string>
|
||||||
|
<string name="revanced_ryd_video_likes_hidden_by_video_owner">Disembunyikan</string>
|
||||||
<!-- PreferenceScreen: Return YouTube Username -->
|
<!-- PreferenceScreen: Return YouTube Username -->
|
||||||
|
<string name="revanced_preference_screen_return_youtube_username_title">Return YouTube Username</string>
|
||||||
|
<string name="revanced_return_youtube_username_enabled_title">Aktifkan Return YouTube Username</string>
|
||||||
|
<string name="revanced_return_youtube_username_enabled_summary">Mengganti penanganan dengan nama pengguna di komentar.</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_title">Format tampilan</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_summary">Pilih format tampilan nama pengguna.</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_username_only">Nama pengguna</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_username_handle">Nama pengguna (@penganganan)</string>
|
||||||
|
<string name="revanced_return_youtube_username_display_format_handle_username">\@penanganan (Nama pengguna)</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_developer_key_title">Kunci API Data YouTube</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_developer_key_summary">Kunci pengembang untuk menggunakan API Data YouTube v3.</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_about_title">Tentang kunci API Data YouTube</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_about_summary">"Kunci Pengembang API Data YouTube v3 diperlukan untuk mengganti penanganan dengan nama pengguna.
|
||||||
|
|
||||||
|
Kuota harian untuk kunci API pada paket gratis adalah 10.000, dan 1 kuota digunakan untuk mengganti penanganan dengan nama pengguna untuk 1 komentar.
|
||||||
|
|
||||||
|
Klik untuk melihat cara menerbitkan kunci API."</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_dialog_title">Terbitkan kunci pengembang API Data YouTube v3</string>
|
||||||
|
<string name="revanced_return_youtube_username_youtube_data_api_v3_dialog_message">1. Pergi ke <a href=%1$s>Buat proyek baru</a>.<br>2. Klik <b>tombol;</b> BUAT.<br>3. Pergi ke <a href=%2$s>API Data YouTube v3</a>.<br>4. Klik <b>tombol</b> NYALAKAN.<br>5. Klik <b>tombol</b> BUAT KREDENSIAL.<br>6. Pilih <b>pilihan</b> data Publik.<br>7. Klik <b>tombol</b> SELANJUTNYA.<br>8. Salin kunci API.<br><br>※ Kunci API tidak boleh dibagikan dengan orang lain, sehingga tidak disertakan dalam pengaturan Impor / Ekspor.</string>
|
||||||
<!-- PreferenceScreen: SponsorBlock -->
|
<!-- PreferenceScreen: SponsorBlock -->
|
||||||
<string name="revanced_preference_screen_sb_title">SponsorBlock</string>
|
<string name="revanced_preference_screen_sb_title">SponsorBlock</string>
|
||||||
<string name="revanced_sb_enabled">Enable SponsorBlock</string>
|
<string name="revanced_sb_enabled">Aktifkan SponsorBlock</string>
|
||||||
<string name="revanced_sb_enabled_sum">SponsorBlock is a crowd-sourced system for skipping annoying parts of YouTube videos.</string>
|
<string name="revanced_sb_enabled_sum">SponsorBlock adalah sistem yang bersumber dari banyak orang untuk melewatkan bagian video YouTube yang mengganggu.</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error">Show a toast if API is unavailable</string>
|
<string name="revanced_sb_toast_on_connection_error">Tampilkan toast jika API tidak tersedia</string>
|
||||||
<string name="revanced_sb_toast_on_connection_error_sum">Shows a toast if the SponsorBlock API is unavailable.</string>
|
<string name="revanced_sb_toast_on_connection_error_sum">Menampilkan toast jika API SponsorBlock tidak tersedia.</string>
|
||||||
<string name="revanced_sb_toast_on_skip">Show a toast when skipping automatically</string>
|
<string name="revanced_sb_toast_on_skip">Menampilkan toast saat melewatkan secara otomatis</string>
|
||||||
<string name="revanced_sb_toast_on_skip_sum">Shows a toast when a segment is automatically skipped.</string>
|
<string name="revanced_sb_toast_on_skip_sum">Menampilkan toast ketika segmen dilewati secara otomatis.</string>
|
||||||
<string name="revanced_sb_api_url">Change API URL</string>
|
<string name="revanced_sb_api_url">Ubah URL API</string>
|
||||||
<string name="revanced_sb_api_url_sum">The address SponsorBlock uses to make calls to the server. Do not change this unless you know what you\'re doing.</string>
|
<string name="revanced_sb_api_url_sum">Alamat yang digunakan SponsorBlock untuk melakukan panggilan ke server. Jangan ubah ini kecuali Anda tahu apa yang Anda lakukan.</string>
|
||||||
<string name="revanced_sb_api_url_reset">API URL reset.</string>
|
<string name="revanced_sb_api_url_reset">URL API diatur ulang.</string>
|
||||||
<string name="revanced_sb_api_url_invalid">API URL is invalid.</string>
|
<string name="revanced_sb_api_url_invalid">URL API tidak sah.</string>
|
||||||
<string name="revanced_sb_api_url_changed">API URL changed.</string>
|
<string name="revanced_sb_api_url_changed">URL API diubah.</string>
|
||||||
<string name="revanced_sb_diff_segments">Change segment behavior</string>
|
<string name="revanced_sb_diff_segments">Ubah perilaku segmen</string>
|
||||||
<string name="revanced_sb_segments_sponsor">Sponsor</string>
|
<string name="revanced_sb_segments_sponsor">Sponsor</string>
|
||||||
<string name="revanced_sb_segments_sponsor_sum">Paid promotion, paid referrals, and direct advertisements. Not for self-promotion or free shout-outs to causes / creators / websites / products they like.</string>
|
<string name="revanced_sb_segments_sponsor_sum">Promosi berbayar, rujukan berbayar, dan iklan langsung. Bukan untuk promosi diri atau promosi gratis untuk tujuan / kreator / situs web / produk yang mereka sukai.</string>
|
||||||
<string name="revanced_sb_segments_selfpromo">Unpaid / Self Promotion</string>
|
<string name="revanced_sb_segments_selfpromo">Tidak Berbayar / Promosi Sendiri</string>
|
||||||
<string name="revanced_sb_segments_selfpromo_sum">Similar to \'Sponsor\' except for unpaid or self promotion. Includes sections about merchandise, donations, or information about who they collaborated with.</string>
|
<string name="revanced_sb_segments_selfpromo_sum">Mirip dengan Sponsor, kecuali untuk promosi yang tidak berbayar atau promosi sendiri. Termasuk bagian tentang barang dagangan, donasi, atau informasi tentang dengan siapa mereka berkolaborasi.</string>
|
||||||
<string name="revanced_sb_segments_interaction">Interaction Reminder (Subscribe)</string>
|
<string name="revanced_sb_segments_interaction">Pengingat Interaksi (Berlangganan)</string>
|
||||||
<string name="revanced_sb_segments_interaction_sum">A short reminder to like, subscribe, or follow them in the middle of content. If it is long or about something specific, it should instead be under self promotion.</string>
|
<string name="revanced_sb_segments_interaction_sum">Pengingat singkat untuk menyukai, berlangganan, atau mengikuti mereka di tengah-tengah konten. Jika panjang atau tentang sesuatu yang spesifik, sebaiknya berada di bawah promosi diri.</string>
|
||||||
<string name="revanced_sb_segments_intro">Intermission / Intro Animation</string>
|
<string name="revanced_sb_segments_intro">Animasi Jeda / Intro</string>
|
||||||
<string name="revanced_sb_segments_intro_sum">An interval without actual content. Could be a pause, static frame, or repeating animation. Does not include transitions containing information.</string>
|
<string name="revanced_sb_segments_intro_sum">Selang waktu tanpa konten yang sebenarnya. Bisa berupa jeda, bingkai statis, atau animasi berulang. Tidak termasuk transisi yang berisi informasi.</string>
|
||||||
<string name="revanced_sb_segments_outro">Endcards / Credits</string>
|
<string name="revanced_sb_segments_outro">Kartu Akhir / Kredit</string>
|
||||||
<string name="revanced_sb_segments_outro_sum">Credits or when the YouTube endcards appear. Not for conclusions with information.</string>
|
<string name="revanced_sb_segments_outro_sum">Kredit atau saat kartu akhir YouTube muncul. Bukan untuk menyimpulkan informasi.</string>
|
||||||
<string name="revanced_sb_segments_preview">Preview / Recap / Hook</string>
|
<string name="revanced_sb_segments_preview">Pratinjau / Rekap / Pengait</string>
|
||||||
<string name="revanced_sb_segments_preview_sum">Collection of clips that show what is coming up or what happened in the video or in other videos of a series, where all information is repeated elsewhere.</string>
|
<string name="revanced_sb_segments_preview_sum">Kumpulan klip yang menunjukkan apa yang akan datang atau apa yang terjadi dalam video atau dalam video lain dari suatu seri, di mana semua informasi diulang di tempat lain.</string>
|
||||||
<string name="revanced_sb_segments_filler">Filler Tangent / Jokes</string>
|
<string name="revanced_sb_segments_filler">Pengisi Tidak Relevan / Lelucon</string>
|
||||||
<string name="revanced_sb_segments_filler_sum">Tangential scenes added only for filler or humor that are not required to understand the main content of the video. Does not include segments providing context or background details.</string>
|
<string name="revanced_sb_segments_filler_sum">Adegan berbelit-belit yang ditambahkan hanya sebagai filler atau candaan yang tidak diperlukan untuk memahami isi utama video. Tidak termasuk bagian yang mengandung konteks atau detail latar belakang.</string>
|
||||||
<string name="revanced_sb_segments_nomusic">Music: Non-Music Section</string>
|
<string name="revanced_sb_segments_nomusic">Musik: Bagian Non-Musik</string>
|
||||||
<string name="revanced_sb_segments_nomusic_sum">Only for use in music videos. Sections of music videos without music, that aren\'t already covered by another category.</string>
|
<string name="revanced_sb_segments_nomusic_sum">Hanya untuk digunakan dalam video musik. Bagian video musik tanpa musik, yang belum tercakup dalam kategori lain.</string>
|
||||||
<string name="revanced_sb_skipped_sponsor">Skipped sponsor.</string>
|
<string name="revanced_sb_skipped_sponsor">Melewatkan sponsor.</string>
|
||||||
<string name="revanced_sb_skipped_selfpromo">Skipped self promotion.</string>
|
<string name="revanced_sb_skipped_selfpromo">Melewatkan promosi diri.</string>
|
||||||
<string name="revanced_sb_skipped_interaction">Skipped annoying reminder.</string>
|
<string name="revanced_sb_skipped_interaction">Melewatkan pengingat mengganggu.</string>
|
||||||
<string name="revanced_sb_skipped_intro_beginning">Skipped intro.</string>
|
<string name="revanced_sb_skipped_intro_beginning">Melewatkan intro.</string>
|
||||||
<string name="revanced_sb_skipped_intro_middle">Skipped intermission.</string>
|
<string name="revanced_sb_skipped_intro_middle">Melewatkan jeda.</string>
|
||||||
<string name="revanced_sb_skipped_intro_end">Skipped intermission.</string>
|
<string name="revanced_sb_skipped_intro_end">Melewatkan jeda.</string>
|
||||||
<string name="revanced_sb_skipped_outro">Skipped outro.</string>
|
<string name="revanced_sb_skipped_outro">Melewatkan outro.</string>
|
||||||
<string name="revanced_sb_skipped_preview_beginning">Skipped preview.</string>
|
<string name="revanced_sb_skipped_preview_beginning">Melewatkan pratinjau.</string>
|
||||||
<string name="revanced_sb_skipped_preview_middle">Skipped preview.</string>
|
<string name="revanced_sb_skipped_preview_middle">Melewatkan pratinjau.</string>
|
||||||
<string name="revanced_sb_skipped_preview_end">Skipped recap.</string>
|
<string name="revanced_sb_skipped_preview_end">Melewatkan rekap.</string>
|
||||||
<string name="revanced_sb_skipped_filler">Skipped filler.</string>
|
<string name="revanced_sb_skipped_filler">Melewatkan pengisi.</string>
|
||||||
<string name="revanced_sb_skipped_nomusic">Skipped a non-music section.</string>
|
<string name="revanced_sb_skipped_nomusic">Melewatkan bagian non musik.</string>
|
||||||
<string name="revanced_sb_skipped_multiple_segments">Skipped multiple segments.</string>
|
<string name="revanced_sb_skipped_multiple_segments">Melewatkan beberapa segmen.</string>
|
||||||
<string name="revanced_sb_skip_automatically">Skip automatically</string>
|
<string name="revanced_sb_skip_automatically">Lewati otomatis</string>
|
||||||
<string name="revanced_sb_skip_ignore">Disable</string>
|
<string name="revanced_sb_skip_ignore">Nonaktifkan</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlock is temporarily unavailable.</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_generic">SponsorBlock untuk sementara tidak tersedia.</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlock is temporarily unavailable (status %d).</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_status">SponsorBlock untuk sementara tidak tersedia (status %d).</string>
|
||||||
<string name="revanced_sb_sponsorblock_connection_failure_timeout">SponsorBlock is temporarily unavailable (API timed out).</string>
|
<string name="revanced_sb_sponsorblock_connection_failure_timeout">SponsorBlock untuk sementara tidak tersedia (API habis batas waktunya).</string>
|
||||||
<string name="revanced_sb_color_dot_label">Color:</string>
|
<string name="revanced_sb_color_dot_label">Warna:</string>
|
||||||
<string name="revanced_sb_color_changed">Color changed.</string>
|
<string name="revanced_sb_color_changed">Warna diubah.</string>
|
||||||
<string name="revanced_sb_color_reset">Color reset.</string>
|
<string name="revanced_sb_color_reset">Warna diatur ulang.</string>
|
||||||
<string name="revanced_sb_color_invalid">Invalid color code. Color reset to default.</string>
|
<string name="revanced_sb_color_invalid">Kode warna tidak sah.</string>
|
||||||
<string name="revanced_sb_reset_color">Reset color</string>
|
<string name="revanced_sb_reset_color">Atur ulang warna</string>
|
||||||
<string name="revanced_sb_about_api_sum">Data is provided by the SponsorBlock API. Tap here to learn more and see downloads for other platforms.</string>
|
<string name="revanced_sb_about_api_sum">Data disediakan oleh API SponsorBlock. Tekan di sini untuk mempelajari lebih lanjut dan melihat unduhan untuk platform lain.</string>
|
||||||
<string name="revanced_sb_about">About</string>
|
<string name="revanced_sb_about">Tentang</string>
|
||||||
<string name="revanced_sb_about_api">sponsor.ajay.app</string>
|
<string name="revanced_sb_about_api">sponsor.ajay.app</string>
|
||||||
<!-- PreferenceScreen: Miscellaneous -->
|
<!-- PreferenceScreen: Miscellaneous -->
|
||||||
<string name="revanced_preference_screen_misc_title">Miscellaneous</string>
|
<string name="revanced_preference_screen_misc_title">Lain-lain</string>
|
||||||
<string name="revanced_extended_settings_import_export_title">Ekspor / Impor</string>
|
<string name="revanced_extended_settings_import_export_title">Ekspor / Impor</string>
|
||||||
<string name="revanced_extended_settings_import_export_summary">Impor atau ekspor setelan sebagai teks.</string>
|
<string name="revanced_extended_settings_import_export_summary">Impor / Ekspor pengaturan Musik RVX.</string>
|
||||||
<string name="revanced_extended_settings_export_as_file">Export settings to file</string>
|
<string name="revanced_extended_settings_export_as_file">Ekspor pengaturan ke berkas</string>
|
||||||
<string name="revanced_extended_settings_import_as_file">Import settings from file</string>
|
<string name="revanced_extended_settings_import_as_file">Impor pengaturan dari berkas</string>
|
||||||
<string name="revanced_extended_settings_import_export_as_text">Import / Export settings as text</string>
|
<string name="revanced_extended_settings_import_export_as_text">Impor / Ekspor pengaturan sebagai teks</string>
|
||||||
<string name="revanced_extended_settings_export_failed">Failed to export settings.</string>
|
<string name="revanced_extended_settings_export_failed">Gagal mengekspor pengaturan.</string>
|
||||||
<string name="revanced_extended_settings_export_success">Settings were successfully exported.</string>
|
<string name="revanced_extended_settings_export_success">Pengaturan berhasil diekspor.</string>
|
||||||
<string name="revanced_extended_settings_import">Impor</string>
|
<string name="revanced_extended_settings_import">Impor</string>
|
||||||
<string name="revanced_extended_settings_import_copy">Salin</string>
|
<string name="revanced_extended_settings_import_copy">Salin</string>
|
||||||
<string name="revanced_extended_settings_import_failed">Import failed: %s.</string>
|
<string name="revanced_extended_settings_import_failed">Impor gagal: %s.</string>
|
||||||
<string name="revanced_extended_settings_import_reset">Reset setelan ke default.</string>
|
<string name="revanced_extended_settings_import_reset">Pengaturan diatur ulang ke bawaan.</string>
|
||||||
<string name="revanced_extended_settings_import_success">Setelan %d diimpor.</string>
|
<string name="revanced_extended_settings_import_success">Setelan %d diimpor.</string>
|
||||||
<string name="revanced_extended_settings_reset">Reset</string>
|
<string name="revanced_extended_settings_reset">Atur ulang</string>
|
||||||
<string name="revanced_share_copy_settings_success">Setelan disalin ke papan klip.</string>
|
<string name="revanced_share_copy_settings_success">Setelan disalin ke papan klip.</string>
|
||||||
<string name="revanced_bypass_image_region_restrictions_title">Bypass gambar larangan wilayah</string>
|
<string name="revanced_bypass_image_region_restrictions_title">Abaikan pembatasan wilayah gambar</string>
|
||||||
<string name="revanced_bypass_image_region_restrictions_summary">Mengganti domain yang ke blokir di negara tertentu sehingga playlist thumbnail, channel avatar, dll bisa di terima.</string>
|
<string name="revanced_bypass_image_region_restrictions_summary">Mengabaikan domain yang diblokir di beberapa wilayah sehingga thumbnail playlist, avatar saluran, dll. dapat diterima.</string>
|
||||||
<string name="revanced_change_share_sheet_title">Ubah lembar berbagi</string>
|
<string name="revanced_change_share_sheet_title">Ubah lembar berbagi</string>
|
||||||
<string name="revanced_change_share_sheet_summary">Mengubah dari lembar berbagi dalam aplikasi ke lembar berbagi sistem.</string>
|
<string name="revanced_change_share_sheet_summary">Mengubah lembar berbagi dalam aplikasi ke lembar berbagi sistem.</string>
|
||||||
|
<string name="revanced_disable_cairo_splash_animation_title">Menonaktifkan animasi percikan Cairo</string>
|
||||||
|
<string name="revanced_disable_cairo_splash_animation_summary">Menonaktifkan animasi percikan Cairo saat aplikasi dimulai.</string>
|
||||||
|
<string name="revanced_disable_drc_audio_title">Nonaktifkan audio DRC</string>
|
||||||
|
<string name="revanced_disable_drc_audio_summary">Menonaktifkan DRC (Dynamic Range Compression) yang diterapkan ke audio.</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_title">Nonaktifkan video musik dalam album</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_summary">"Ketika pengguna non-premium memutar lagu yang termasuk dalam album, video musik terkadang diputar dan bukannya lagu resminya.
|
||||||
|
|
||||||
|
Temukan lagu resmi jika video musik terdeteksi diputar dari album.
|
||||||
|
|
||||||
|
Keterbatasan: Video anak-anak mungkin tidak dapat dialihkan."</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_title">Jenis pengalihan</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_summary">Menentukan cara mengalihkan ke lagu resmi.</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">Alihkan</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">Ketuk tombol Lagu / Video</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">Ketuk dan tahan tombol Lagu / Video</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_title">Nonaktifkan protokol QUIC</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_summary">"Menonaktifkan protokol QUIC CronetEngine."</string>
|
||||||
<string name="revanced_enable_debug_logging_title">Aktifkan pencatatan debug</string>
|
<string name="revanced_enable_debug_logging_title">Aktifkan pencatatan debug</string>
|
||||||
<string name="revanced_enable_debug_logging_summary">Mencetak catatan debug.</string>
|
<string name="revanced_enable_debug_logging_summary">Mencetak catatan debug.</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_title">Enable debug buffer logging</string>
|
<string name="revanced_enable_debug_buffer_logging_title">Mengaktifkan pencatatan buffer debug</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_summary">Includes the buffer in the debug log.</string>
|
<string name="revanced_enable_debug_buffer_logging_summary">Menyertakan buffer dalam log debug.</string>
|
||||||
<string name="revanced_enable_opus_codec_title">Aktifkan codec opus</string>
|
<string name="revanced_enable_opus_codec_title">Aktifkan codec opus</string>
|
||||||
<string name="revanced_enable_opus_codec_summary">"Mengaktifkan codec audio opus alih-alih codec audio mp4a."</string>
|
<string name="revanced_enable_opus_codec_summary">"Mengaktifkan codec OPUS jika respon pemutar menyertakannya.
|
||||||
<string name="revanced_sanitize_sharing_links_title">Sanitasi tautan berbagi</string>
|
|
||||||
<string name="revanced_sanitize_sharing_links_summary">Menghapus parameter kueri pelacakan dari URL saat membagikan tautan.</string>
|
|
||||||
<string name="gms_core_settings_title">Open GmsCore</string>
|
|
||||||
<string name="gms_core_settings_summary">Enable cloud messaging to receive notifications.</string>
|
|
||||||
<string name="gms_core_toast_not_installed_message">GmsCore is not installed. Install it.</string>
|
|
||||||
<string name="gms_core_dialog_title">Action needed</string>
|
|
||||||
<string name="gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"GmsCore does not have permission to run in the background.
|
|
||||||
|
|
||||||
Follow the 'Don't kill my app!' guide for your device, and apply the instructions to your GmsCore installation.
|
Info:
|
||||||
|
• Klien YouTube Music terbaru menggunakan codec audio OPUS secara default.
|
||||||
|
• Ini hanya berlaku untuk pengguna yang memalsukan dengan klien yang sangat lama."</string>
|
||||||
|
<string name="revanced_sanitize_sharing_links_title">Bersihkan tautan berbagi</string>
|
||||||
|
<string name="revanced_sanitize_sharing_links_summary">Membersihkan tautan berbagi dengan menghapus parameter kueri pelacakan.</string>
|
||||||
|
<string name="revanced_spoof_client_title">Palsukan klien</string>
|
||||||
|
<string name="revanced_spoof_client_summary">Memalsukan klien untuk mencegah masalah pemutaran.</string>
|
||||||
|
<string name="revanced_spoof_client_type_title">Klien bawaan</string>
|
||||||
|
<string name="revanced_spoof_client_type_summary">Menentukan klien bawaan untuk pemalsuan.</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_android_music_4_27">Musik Android 4.27.53</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Musik Android 5.29.53</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">Musik iOS 6.21</string>
|
||||||
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">Musik iOS 7.04</string>
|
||||||
|
<string name="revanced_watch_history_type_title">Jenis riwayat tontonan</string>
|
||||||
|
<string name="revanced_watch_history_type_summary">"• Asli: Mengikuti pengaturan riwayat tontonan akun Google, tetapi riwayat tontonan mungkin tidak berfungsi karena DNS atau VPN.
|
||||||
|
• Ganti domain: Mengikuti pengaturan riwayat tontonan akun Google.
|
||||||
|
• Blokir riwayat tontonan: Riwayat tontonan diblokir."</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_1">Asli</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_2">Ganti domain</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_3">Blokir riwayat tontonan</string>
|
||||||
|
<string name="revanced_default_app_settings_title">Buka pengaturan aplikasi bawaan</string>
|
||||||
|
<string name="revanced_default_app_settings_summary">Untuk membuka tautan YouTube Music di RVX Music, aktifkan Buka tautan yang didukung dan aktifkan semua alamat web yang Didukung.</string>
|
||||||
|
<string name="gms_core_settings_title">Buka pengaturan GmsCore</string>
|
||||||
|
<string name="gms_core_settings_summary">Untuk menerima pemberitahuan di RVX Music, aktifkan Cloud Messaging.</string>
|
||||||
|
<string name="gms_core_toast_not_installed_message">GmsCore tidak terpasang. Pasang dulu.</string>
|
||||||
|
<string name="gms_core_dialog_title">Diperlukan tindakan</string>
|
||||||
|
<string name="gms_core_dialog_not_whitelisted_not_allowed_in_background_message">"GmsCore tidak memiliki izin untuk berjalan di latar belakang.
|
||||||
|
|
||||||
This is required for the app to work."</string>
|
Ikuti panduan 'Don't kill my app!' untuk perangkat Anda, dan terapkan petunjuk pada pemasangan GmsCore.
|
||||||
<string name="gms_core_dialog_open_website_text">Open website</string>
|
|
||||||
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"GmsCore battery optimizations must be disabled to prevent issues.
|
|
||||||
|
|
||||||
Tap on the continue button and disable battery optimizations."</string>
|
Hal ini diperlukan agar aplikasi dapat berfungsi."</string>
|
||||||
<string name="gms_core_dialog_continue_text">Continue</string>
|
<string name="gms_core_dialog_open_website_text">Buka website</string>
|
||||||
|
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"Pengoptimalan baterai GmsCore harus dinonaktifkan untuk mencegah masalah.
|
||||||
|
|
||||||
|
Menonaktifkan pengoptimalan baterai untuk GmsCore tidak akan berdampak negatif pada penggunaan baterai.
|
||||||
|
|
||||||
|
Ketuk tombol lanjutkan dan izinkan perubahan pengoptimalan."</string>
|
||||||
|
<string name="gms_core_dialog_continue_text">Lanjutkan</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -54,6 +54,11 @@
|
|||||||
<!-- PreferenceScreen: Ads -->
|
<!-- PreferenceScreen: Ads -->
|
||||||
<string name="revanced_preference_screen_ads_title">広告</string>
|
<string name="revanced_preference_screen_ads_title">広告</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_title">全画面広告を非表示</string>
|
<string name="revanced_hide_fullscreen_ads_title">全画面広告を非表示</string>
|
||||||
|
<string name="revanced_hide_fullscreen_ads_summary">"全画面広告を隠す
|
||||||
|
|
||||||
|
注意:
|
||||||
|
・ホームフィードの代わりに真っ黒な画面が表示されることがあります。"</string>
|
||||||
|
<string name="revanced_fullscreen_ads_closed_toast">全画面広告を閉じました。</string>
|
||||||
<string name="revanced_hide_general_ads_title">一般広告を非表示</string>
|
<string name="revanced_hide_general_ads_title">一般広告を非表示</string>
|
||||||
<string name="revanced_hide_general_ads_summary">一般広告を非表示にします。</string>
|
<string name="revanced_hide_general_ads_summary">一般広告を非表示にします。</string>
|
||||||
<string name="revanced_hide_music_ads_title">音楽の広告を非表示</string>
|
<string name="revanced_hide_music_ads_title">音楽の広告を非表示</string>
|
||||||
@ -62,6 +67,7 @@
|
|||||||
<string name="revanced_hide_paid_promotion_label_summary">有料プロモーションラベルを非表示にします。</string>
|
<string name="revanced_hide_paid_promotion_label_summary">有料プロモーションラベルを非表示にします。</string>
|
||||||
<string name="revanced_hide_premium_promotion_title">プレミアムプロモーションポップアップを非表示</string>
|
<string name="revanced_hide_premium_promotion_title">プレミアムプロモーションポップアップを非表示</string>
|
||||||
<string name="revanced_hide_premium_promotion_summary">プレミアムプロモーションポップアップを非表示にします。</string>
|
<string name="revanced_hide_premium_promotion_summary">プレミアムプロモーションポップアップを非表示にします。</string>
|
||||||
|
<string name="revanced_hide_premium_promotion_closed_toast">プレミアムプロモーションのポップアップは閉じられました。</string>
|
||||||
<string name="revanced_hide_premium_renewal_title">プレミアム更新バナーを非表示</string>
|
<string name="revanced_hide_premium_renewal_title">プレミアム更新バナーを非表示</string>
|
||||||
<string name="revanced_hide_premium_renewal_summary">プレミアム更新バナーを非表示にします。</string>
|
<string name="revanced_hide_premium_renewal_summary">プレミアム更新バナーを非表示にします。</string>
|
||||||
<string name="revanced_hide_promotion_alert_banner_title">プロモーションバナーを非表示</string>
|
<string name="revanced_hide_promotion_alert_banner_title">プロモーションバナーを非表示</string>
|
||||||
@ -93,6 +99,7 @@
|
|||||||
<string name="revanced_hide_flyout_menu_go_to_episode_title">「エピソードに移動」を非表示</string>
|
<string name="revanced_hide_flyout_menu_go_to_episode_title">「エピソードに移動」を非表示</string>
|
||||||
<string name="revanced_hide_flyout_menu_go_to_podcast_title">「ポッドキャストに移動」を非表示</string>
|
<string name="revanced_hide_flyout_menu_go_to_podcast_title">「ポッドキャストに移動」を非表示</string>
|
||||||
<string name="revanced_hide_flyout_menu_help_title">「ヘルプとフィードバック」を非表示</string>
|
<string name="revanced_hide_flyout_menu_help_title">「ヘルプとフィードバック」を非表示</string>
|
||||||
|
<string name="revanced_hide_flyout_menu_not_interested_title">「興味なし」を非表示</string>
|
||||||
<string name="revanced_hide_flyout_menu_pin_to_speed_dial_title">「[クイック アクセス] に固定」を非表示</string>
|
<string name="revanced_hide_flyout_menu_pin_to_speed_dial_title">「[クイック アクセス] に固定」を非表示</string>
|
||||||
<string name="revanced_hide_flyout_menu_play_next_title">「次に再生」を非表示</string>
|
<string name="revanced_hide_flyout_menu_play_next_title">「次に再生」を非表示</string>
|
||||||
<string name="revanced_hide_flyout_menu_quality_title">画質メニューを非表示</string>
|
<string name="revanced_hide_flyout_menu_quality_title">画質メニューを非表示</string>
|
||||||
@ -124,8 +131,17 @@
|
|||||||
<string name="revanced_preference_screen_general_title">全般</string>
|
<string name="revanced_preference_screen_general_title">全般</string>
|
||||||
<string name="revanced_change_start_page_title">スタートページを変更</string>
|
<string name="revanced_change_start_page_title">スタートページを変更</string>
|
||||||
<string name="revanced_change_start_page_summary">アプリのスタートページを変更します。</string>
|
<string name="revanced_change_start_page_summary">アプリのスタートページを変更します。</string>
|
||||||
|
<string name="revanced_change_start_page_entry_default">デフォルト</string>
|
||||||
|
<string name="revanced_change_start_page_entry_charts">チャート</string>
|
||||||
|
<string name="revanced_change_start_page_entry_episodes_for_later">次に再生</string>
|
||||||
<string name="revanced_change_start_page_entry_explore">探索</string>
|
<string name="revanced_change_start_page_entry_explore">探索</string>
|
||||||
|
<string name="revanced_change_start_page_entry_history">履歴</string>
|
||||||
<string name="revanced_change_start_page_entry_library">ライブラリ</string>
|
<string name="revanced_change_start_page_entry_library">ライブラリ</string>
|
||||||
|
<string name="revanced_change_start_page_entry_liked_music">高く評価した音楽</string>
|
||||||
|
<string name="revanced_change_start_page_entry_podcasts">ポッドキャスト</string>
|
||||||
|
<string name="revanced_change_start_page_entry_samples">サンプル</string>
|
||||||
|
<string name="revanced_change_start_page_entry_search">検索</string>
|
||||||
|
<string name="revanced_change_start_page_entry_subscriptions">登録チャンネル</string>
|
||||||
<string name="revanced_disable_dislike_redirection_title">低評価リダイレクトを無効化</string>
|
<string name="revanced_disable_dislike_redirection_title">低評価リダイレクトを無効化</string>
|
||||||
<string name="revanced_disable_dislike_redirection_summary">低評価ボタンを押したとき、次の曲へのリダイレクトするのを無効にする。</string>
|
<string name="revanced_disable_dislike_redirection_summary">低評価ボタンを押したとき、次の曲へのリダイレクトするのを無効にする。</string>
|
||||||
<string name="revanced_disable_auto_captions_title">字幕の強制を無効化</string>
|
<string name="revanced_disable_auto_captions_title">字幕の強制を無効化</string>
|
||||||
@ -197,6 +213,18 @@
|
|||||||
<string name="revanced_hide_navigation_bar_summary">ナビゲーションバーを非表示にします。</string>
|
<string name="revanced_hide_navigation_bar_summary">ナビゲーションバーを非表示にします。</string>
|
||||||
<string name="revanced_hide_navigation_label_title">ナビゲーションバーのラベルを非表示</string>
|
<string name="revanced_hide_navigation_label_title">ナビゲーションバーのラベルを非表示</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">ナビゲーションバーのラベルを非表示にします。</string>
|
<string name="revanced_hide_navigation_label_summary">ナビゲーションバーのラベルを非表示にします。</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">サンプルボタンを置換</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">「サンプル」を「検索」に置き換えます。</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">アップグレードボタンを置換</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">「アップグレード」を「設定」に置き換えます。</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">ボタンの置き換えについて</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"この機能は実験的なものです。
|
||||||
|
YouTube Music の検索や設定などのアクティビティは公開されていないため、このパッチには構造的な制限があります。
|
||||||
|
|
||||||
|
既知の問題:
|
||||||
|
・検索や設定などの置換されたアクティビティを閉じると、スタートページが開きます。
|
||||||
|
|
||||||
|
クリックすると「スタートページの変更」設定が開きます。"</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">プレーヤー</string>
|
<string name="revanced_preference_screen_player_title">プレーヤー</string>
|
||||||
<string name="revanced_add_miniplayer_next_button_title">「次の曲に進むボタン」を表示</string>
|
<string name="revanced_add_miniplayer_next_button_title">「次の曲に進むボタン」を表示</string>
|
||||||
@ -222,8 +250,14 @@
|
|||||||
<string name="revanced_disable_miniplayer_gesture_summary">ミニプレイヤーでスワイプによる曲の変更を無効にします。</string>
|
<string name="revanced_disable_miniplayer_gesture_summary">ミニプレイヤーでスワイプによる曲の変更を無効にします。</string>
|
||||||
<string name="revanced_disable_player_gesture_title">プレイヤージェスチャーを無効にする</string>
|
<string name="revanced_disable_player_gesture_title">プレイヤージェスチャーを無効にする</string>
|
||||||
<string name="revanced_disable_player_gesture_summary">プレイヤーでスワイプによる曲の変更を無効にします。</string>
|
<string name="revanced_disable_player_gesture_summary">プレイヤーでスワイプによる曲の変更を無効にします。</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_title">ミニプレイヤーの強制</string>
|
||||||
|
<string name="revanced_enable_forced_miniplayer_summary">新しいトラックに切り替えたときに強制的にミニプレーヤーを有効にします。</string>
|
||||||
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">スワイプしてミニプレーヤーを閉じる</string>
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">スワイプしてミニプレーヤーを閉じる</string>
|
||||||
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">下にスワイプしてミニプレーヤーを閉じられるようにします。</string>
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">下にスワイプしてミニプレーヤーを閉じられるようにします。</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_title">太いシークバーを有効化</string>
|
||||||
|
<string name="revanced_enable_thick_seekbar_summary">"太いシークバーを有効にします。
|
||||||
|
|
||||||
|
注意: SponsorBlock セグメントはシークバーに表示されません。"</string>
|
||||||
<string name="revanced_enable_zen_mode_title">Zen モードを有効化</string>
|
<string name="revanced_enable_zen_mode_title">Zen モードを有効化</string>
|
||||||
<string name="revanced_enable_zen_mode_summary">動画プレーヤーに灰色の色合いを追加し、目の疲れを軽減します。</string>
|
<string name="revanced_enable_zen_mode_summary">動画プレーヤーに灰色の色合いを追加し、目の疲れを軽減します。</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_title">ポッドキャストでZenモードを有効化</string>
|
<string name="revanced_enable_zen_mode_podcast_title">ポッドキャストでZenモードを有効化</string>
|
||||||
@ -399,11 +433,18 @@ API キーの発行方法については、ここをタップしてください
|
|||||||
<string name="revanced_disable_drc_audio_title">DRCオーディオを無効にする</string>
|
<string name="revanced_disable_drc_audio_title">DRCオーディオを無効にする</string>
|
||||||
<string name="revanced_disable_drc_audio_summary">音声に適用されるDRC (Dynamic Range Compression) を無効にします。</string>
|
<string name="revanced_disable_drc_audio_summary">音声に適用されるDRC (Dynamic Range Compression) を無効にします。</string>
|
||||||
<string name="revanced_disable_music_video_in_album_title">アルバム内のミュージックビデオを無効にする</string>
|
<string name="revanced_disable_music_video_in_album_title">アルバム内のミュージックビデオを無効にする</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_summary">"非プレミアムユーザーがアルバムに含まれる曲を再生すると、公式の曲ではなくMVが再生されることがあります。
|
||||||
|
|
||||||
|
アルバムからMVの再生が検出された場合は、公式楽曲を検索します。
|
||||||
|
|
||||||
|
注意: キッズビデオはリダイレクトされない場合があります。"</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_title">リダイレクトのタイプ</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_title">リダイレクトのタイプ</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_summary">公式楽曲にリダイレクトする方法を指定します。</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_summary">公式楽曲にリダイレクトする方法を指定します。</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">リダイレクト</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">リダイレクト</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">曲 / 動画 の切り替えをタップ</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">曲 / 動画 の切り替えをタップ</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">曲 / 動画 の切り替えをタップし長押し</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">曲 / 動画 の切り替えをタップし長押し</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_title">QUIC プロトコルを無効化</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_summary">"CronetEngine の QUIC プロトコルを無効化します。"</string>
|
||||||
<string name="revanced_enable_debug_logging_title">デバッグログ</string>
|
<string name="revanced_enable_debug_logging_title">デバッグログ</string>
|
||||||
<string name="revanced_enable_debug_logging_summary">デバッグログを出力します。</string>
|
<string name="revanced_enable_debug_logging_summary">デバッグログを出力します。</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_title">デバッグバッファログを有効化</string>
|
<string name="revanced_enable_debug_buffer_logging_title">デバッグバッファログを有効化</string>
|
||||||
@ -415,10 +456,23 @@ API キーの発行方法については、ここをタップしてください
|
|||||||
<string name="revanced_spoof_client_title">クライアントを偽装</string>
|
<string name="revanced_spoof_client_title">クライアントを偽装</string>
|
||||||
<string name="revanced_spoof_client_summary">再生の問題を防ぐためにクライアントを偽装します。</string>
|
<string name="revanced_spoof_client_summary">再生の問題を防ぐためにクライアントを偽装します。</string>
|
||||||
<string name="revanced_spoof_client_type_title">既定のクライアント</string>
|
<string name="revanced_spoof_client_type_title">既定のクライアント</string>
|
||||||
|
<string name="revanced_spoof_client_type_summary">偽装するデフォルトのクライアントを定義します。</string>
|
||||||
<string name="revanced_spoof_client_type_entry_android_music_4_27">Android Music 4.27.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_4_27">Android Music 4.27.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">プレイヤーパラメータを偽装</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"再生の問題を防ぐためにプレイヤーパラメーターを偽装します。
|
||||||
|
|
||||||
|
副作用:
|
||||||
|
• 字幕が下部ではなくプレーヤーの上部に配置されることがあります。"</string>
|
||||||
|
<string name="revanced_watch_history_type_title">再生履歴の種類</string>
|
||||||
|
<string name="revanced_watch_history_type_summary">"・オリジナル: Google アカウントの視聴履歴設定に従いますが、DNSやVPNにより視聴履歴が機能しない場合があります。
|
||||||
|
・ドメインを置き換えます: Google アカウントの視聴履歴設定に従います。
|
||||||
|
・視聴履歴をブロックします: 視聴履歴をブロックします。"</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_1">オリジナル</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_2">ドメインを置換</string>
|
||||||
|
<string name="revanced_watch_history_type_entry_3">再生履歴をブロック</string>
|
||||||
<string name="revanced_default_app_settings_title">「デフォルトで開く」の設定</string>
|
<string name="revanced_default_app_settings_title">「デフォルトで開く」の設定</string>
|
||||||
<string name="revanced_default_app_settings_summary">RVX Music でYouTube Music のURLを開くには、「対応リンクを開く」を有効にし、サポートされているURLを有効にします。</string>
|
<string name="revanced_default_app_settings_summary">RVX Music でYouTube Music のURLを開くには、「対応リンクを開く」を有効にし、サポートされているURLを有効にします。</string>
|
||||||
<string name="gms_core_settings_title">GmsCoreを開く</string>
|
<string name="gms_core_settings_title">GmsCoreを開く</string>
|
||||||
|
@ -212,6 +212,18 @@
|
|||||||
<string name="revanced_hide_navigation_bar_summary">하단바를 숨깁니다.</string>
|
<string name="revanced_hide_navigation_bar_summary">하단바를 숨깁니다.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">하단바 버튼 라벨 제거</string>
|
<string name="revanced_hide_navigation_label_title">하단바 버튼 라벨 제거</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">하단바 버튼에서 라벨을 숨깁니다.</string>
|
<string name="revanced_hide_navigation_label_summary">하단바 버튼에서 라벨을 숨깁니다.</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">샘플 버튼 변경</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">샘플 버튼을 검색 버튼으로 변경합니다.</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">업그레이드 버튼 변경</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">업그레이드 버튼을 설정 버튼으로 변경합니다.</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">버튼 변경에 대한 정보</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"이 기능은 실험 기능입니다.
|
||||||
|
YouTube Music의 검색 및 설정과 같은 활동은 공개되지 않으므로 패치에는 구조적인 제한이 있습니다.
|
||||||
|
|
||||||
|
알려진 문제:
|
||||||
|
• 검색 및 설정과 같은 교체된 활동이 닫히면 앱 시작 페이지가 열립니다.
|
||||||
|
|
||||||
|
앱 시작 페이지 설정을 열려면 여기를 누르세요."</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">플레이어</string>
|
<string name="revanced_preference_screen_player_title">플레이어</string>
|
||||||
<string name="revanced_add_miniplayer_next_button_title">미니 플레이어 다음 재생 버튼 추가</string>
|
<string name="revanced_add_miniplayer_next_button_title">미니 플레이어 다음 재생 버튼 추가</string>
|
||||||
@ -426,7 +438,7 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요."</string>
|
|||||||
앨범에서 뮤직 비디오가 재생되는 것이 감지되면 정식 음원을 찾아줍니다.
|
앨범에서 뮤직 비디오가 재생되는 것이 감지되면 정식 음원을 찾아줍니다.
|
||||||
|
|
||||||
알려진 문제점:
|
알려진 문제점:
|
||||||
• Kids 동영상은 리디렉션되지 않을 수 있습니다."</string>
|
• Kids 동영상은 리다이렉션되지 않을 수 있습니다."</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_title">리다이렉션 유형</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_title">리다이렉션 유형</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_summary">정식 음원으로 리다이렉션하는 방법을 지정할 수 있습니다.</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_summary">정식 음원으로 리다이렉션하는 방법을 지정할 수 있습니다.</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">리다이렉션</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">리다이렉션</string>
|
||||||
@ -454,6 +466,11 @@ API Key를 발급받는 방법을 보려면 여기를 누르세요."</string>
|
|||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">플레이어 매개변수 변경하기</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"플레이어 매개변수를 변경하여 재생 문제를 방지할 수 있습니다.
|
||||||
|
|
||||||
|
알려진 문제점:
|
||||||
|
• 자막이 플레이어 하단이 아닌 상단에 위치하는 경우가 있습니다."</string>
|
||||||
<string name="revanced_watch_history_type_title">시청 기록 유형</string>
|
<string name="revanced_watch_history_type_title">시청 기록 유형</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• 기본값: Google 계정의 시청 기록 설정을 따르지만 DNS 또는 VPN으로 인하여 시청 기록이 작동되지 않을 수 있습니다.
|
<string name="revanced_watch_history_type_summary">"• 기본값: Google 계정의 시청 기록 설정을 따르지만 DNS 또는 VPN으로 인하여 시청 기록이 작동되지 않을 수 있습니다.
|
||||||
• 도메인 변경: Google 계정의 시청 기록 설정을 따릅니다.
|
• 도메인 변경: Google 계정의 시청 기록 설정을 따릅니다.
|
||||||
|
@ -213,6 +213,18 @@ Nie pomija to ograniczeń wiekowych, lecz akceptuje je automatycznie."</string>
|
|||||||
<string name="revanced_hide_navigation_bar_summary">Ukrywa pasek nawigacji.</string>
|
<string name="revanced_hide_navigation_bar_summary">Ukrywa pasek nawigacji.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Ukryj nazwy w pasku nawigacji</string>
|
<string name="revanced_hide_navigation_label_title">Ukryj nazwy w pasku nawigacji</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Ukrywa nazwy każdego przycisku w pasku nawigacji.</string>
|
<string name="revanced_hide_navigation_label_summary">Ukrywa nazwy każdego przycisku w pasku nawigacji.</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">Zastąp przycisk sampli</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">Zastępuje przycisk sampli przyciskiem wyszukiwania.</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">Zastąp przycisk przejścia na YouTube Premium</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">Zastępuje przycisk przejścia na YouTube Premium przyciskiem ustawień.</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">O zastępowaniu przycisków</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"Ta funkcja jest eksperymentalna.
|
||||||
|
Istnieją strukturalne ograniczenia łatki, ponieważ działania takie jak wyszukiwanie i ustawienia w YouTube Music nie są publiczne.
|
||||||
|
|
||||||
|
Znane problemy:
|
||||||
|
• Po zamknięciu zastąpionego działania, takiego jak wyszukiwanie i ustawienia, otwierana jest strona startowa.
|
||||||
|
|
||||||
|
Kliknij, by otworzyć ustawienia 'Zmień stronę startową'."</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Odtwarzacz</string>
|
<string name="revanced_preference_screen_player_title">Odtwarzacz</string>
|
||||||
<string name="revanced_add_miniplayer_next_button_title">Dodaj przycisk do następnego utworu w miniodtwarzaczu</string>
|
<string name="revanced_add_miniplayer_next_button_title">Dodaj przycisk do następnego utworu w miniodtwarzaczu</string>
|
||||||
@ -453,6 +465,11 @@ Informacje:
|
|||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">Oszukuj parametry odtwarzacza</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"Oszukuje parametry odtwarzacza, by zapobiec problemom z odtwarzaniem.
|
||||||
|
|
||||||
|
Efekt uboczny:
|
||||||
|
• Czasem napisy są u góry odtwarzacza, zamiast na dole"</string>
|
||||||
<string name="revanced_watch_history_type_title">Typ historii oglądania</string>
|
<string name="revanced_watch_history_type_title">Typ historii oglądania</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• Oryginalny: Stosuje się do ustawień historii oglądania konta Google, lecz historia oglądania może nie działać przy używaniu DNS lub VPN
|
<string name="revanced_watch_history_type_summary">"• Oryginalny: Stosuje się do ustawień historii oglądania konta Google, lecz historia oglądania może nie działać przy używaniu DNS lub VPN
|
||||||
• Zastąpienie domeny: Stosuje się do ustawień historii oglądania konta Google
|
• Zastąpienie domeny: Stosuje się do ustawień historii oglądania konta Google
|
||||||
|
@ -54,6 +54,10 @@ Por favor, baixe %2$s do site."</string>
|
|||||||
<!-- PreferenceScreen: Ads -->
|
<!-- PreferenceScreen: Ads -->
|
||||||
<string name="revanced_preference_screen_ads_title">Anúncios</string>
|
<string name="revanced_preference_screen_ads_title">Anúncios</string>
|
||||||
<string name="revanced_hide_fullscreen_ads_title">Ocultar anúncios em tela cheia</string>
|
<string name="revanced_hide_fullscreen_ads_title">Ocultar anúncios em tela cheia</string>
|
||||||
|
<string name="revanced_hide_fullscreen_ads_summary">"Oculta anúncios de tela cheia.
|
||||||
|
|
||||||
|
Limitações:
|
||||||
|
• Às vezes você pode ver uma tela preta em branco ao invés do feed inicial."</string>
|
||||||
<string name="revanced_fullscreen_ads_closed_toast">Os anúncios em tela cheia são fechados.</string>
|
<string name="revanced_fullscreen_ads_closed_toast">Os anúncios em tela cheia são fechados.</string>
|
||||||
<string name="revanced_hide_general_ads_title">Ocultar anúncios gerais</string>
|
<string name="revanced_hide_general_ads_title">Ocultar anúncios gerais</string>
|
||||||
<string name="revanced_hide_general_ads_summary">Oculta anúncios gerais.</string>
|
<string name="revanced_hide_general_ads_summary">Oculta anúncios gerais.</string>
|
||||||
@ -239,7 +243,9 @@ Use cores escuras se possível, pois o aplicativo não suporta temas claros."</s
|
|||||||
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">Ativar deslizar para dispensar o mini reprodutor</string>
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_title">Ativar deslizar para dispensar o mini reprodutor</string>
|
||||||
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">Ativa deslizar para baixo para fechar o mini reprodutor.</string>
|
<string name="revanced_enable_swipe_to_dismiss_miniplayer_summary">Ativa deslizar para baixo para fechar o mini reprodutor.</string>
|
||||||
<string name="revanced_enable_thick_seekbar_title">Ativar barra de busca espessa</string>
|
<string name="revanced_enable_thick_seekbar_title">Ativar barra de busca espessa</string>
|
||||||
<string name="revanced_enable_thick_seekbar_summary">"Ativa a barra de busca espessa."</string>
|
<string name="revanced_enable_thick_seekbar_summary">"Ativar a barra de busca espessa.
|
||||||
|
|
||||||
|
Limitações: segmentos de patrocinadores não são exibidos na barra de busca."</string>
|
||||||
<string name="revanced_enable_zen_mode_title">Ativar modo Calmo</string>
|
<string name="revanced_enable_zen_mode_title">Ativar modo Calmo</string>
|
||||||
<string name="revanced_enable_zen_mode_summary">Ativa uma cor cinza claro para o fundo do reprodutor para reduzir o cansaço visual.</string>
|
<string name="revanced_enable_zen_mode_summary">Ativa uma cor cinza claro para o fundo do reprodutor para reduzir o cansaço visual.</string>
|
||||||
<string name="revanced_enable_zen_mode_podcast_title">Ativar o modo Calmo em podcasts</string>
|
<string name="revanced_enable_zen_mode_podcast_title">Ativar o modo Calmo em podcasts</string>
|
||||||
@ -415,11 +421,18 @@ Clique para ver como emitir uma chave de API."</string>
|
|||||||
<string name="revanced_disable_drc_audio_title">Desativar áudio DRC</string>
|
<string name="revanced_disable_drc_audio_title">Desativar áudio DRC</string>
|
||||||
<string name="revanced_disable_drc_audio_summary">Desativa o DRC (Compressão de faixa dinâmica) aplicada ao áudio.</string>
|
<string name="revanced_disable_drc_audio_summary">Desativa o DRC (Compressão de faixa dinâmica) aplicada ao áudio.</string>
|
||||||
<string name="revanced_disable_music_video_in_album_title">Desativar vídeo da música no álbum</string>
|
<string name="revanced_disable_music_video_in_album_title">Desativar vídeo da música no álbum</string>
|
||||||
|
<string name="revanced_disable_music_video_in_album_summary">"Quando um usuário não premium reproduz uma música incluída em um álbum, o vídeo da música é tocado às vezes em vez da música oficial.
|
||||||
|
|
||||||
|
Encontre a música oficial se um vídeo de música for detectado tocando de um álbum.
|
||||||
|
|
||||||
|
Limitações: Vídeos infantis não podem ser redirecionados."</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_title">Tipo de redirecionamento</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_title">Tipo de redirecionamento</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_summary">Especifica como redirecionar para a música oficial.</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_summary">Especifica como redirecionar para a música oficial.</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">Redirecionar</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_redirect">Redirecionar</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">Tocar alternador de Música / Vídeo</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_click">Tocar alternador de Música / Vídeo</string>
|
||||||
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">Tocar e segurar alternador de Música / Vídeo</string>
|
<string name="revanced_disable_music_video_in_album_redirect_type_entry_on_long_click">Tocar e segurar alternador de Música / Vídeo</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_title">Desativar protocolo QUIC</string>
|
||||||
|
<string name="revanced_disable_quic_protocol_summary">"Desativa o protocolo QUIC da CronetEngine."</string>
|
||||||
<string name="revanced_enable_debug_logging_title">Ativar o relatório de depuração</string>
|
<string name="revanced_enable_debug_logging_title">Ativar o relatório de depuração</string>
|
||||||
<string name="revanced_enable_debug_logging_summary">Imprime o relatório de depuração</string>
|
<string name="revanced_enable_debug_logging_summary">Imprime o relatório de depuração</string>
|
||||||
<string name="revanced_enable_debug_buffer_logging_title">Ativar o registro de depuração do buffer</string>
|
<string name="revanced_enable_debug_buffer_logging_title">Ativar o registro de depuração do buffer</string>
|
||||||
|
@ -213,6 +213,18 @@
|
|||||||
<string name="revanced_hide_navigation_bar_summary">Скрывает панель навигации.</string>
|
<string name="revanced_hide_navigation_bar_summary">Скрывает панель навигации.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Скрыть подписи кнопок навигации</string>
|
<string name="revanced_hide_navigation_label_title">Скрыть подписи кнопок навигации</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Скрывает подписи под кнопками навигации.</string>
|
<string name="revanced_hide_navigation_label_summary">Скрывает подписи под кнопками навигации.</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">Замена кнопки \"Сэмплы\"</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">Заменяет кнопку \"Сэмпли\" на кнопку \"Поиск\".</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">Замена кнопки \"Обновить\"</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">Заменяет кнопку \"Обновить\" на кнопку \"Настройки\".</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">О замене кнопки</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"Эта функция является экспериментальной.
|
||||||
|
Такие действия, как Поиск и Настройки в YouTube Music, не являются общедоступными, поэтому патч имеет структурные ограничения.
|
||||||
|
|
||||||
|
Известные проблемы:
|
||||||
|
• При закрытии замененных действий, таких как Поиск и Настройки, открывается начальная страница.
|
||||||
|
|
||||||
|
Нажмите, чтобы открыть \"Изменить начальную страницу\"."</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Плеер</string>
|
<string name="revanced_preference_screen_player_title">Плеер</string>
|
||||||
<string name="revanced_add_miniplayer_next_button_title">Добавить кнопку следующее в миниплеер</string>
|
<string name="revanced_add_miniplayer_next_button_title">Добавить кнопку следующее в миниплеер</string>
|
||||||
@ -451,6 +463,11 @@
|
|||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">Подменить параметр плеера</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"Подменяет параметр плеера, чтобы предотвратить проблемы с воспроизведением.
|
||||||
|
|
||||||
|
Побочный эффект:
|
||||||
|
• Иногда субтитры располагаются в верхней части плеера, а не в нижней."</string>
|
||||||
<string name="revanced_watch_history_type_title">Тип истории просмотра</string>
|
<string name="revanced_watch_history_type_title">Тип истории просмотра</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• Оригинальный: Соответствует настройкам истории просмотров аккаунта Google, но история просмотров может не работать через DNS или VPN.
|
<string name="revanced_watch_history_type_summary">"• Оригинальный: Соответствует настройкам истории просмотров аккаунта Google, но история просмотров может не работать через DNS или VPN.
|
||||||
• Заменить домен: Настройка истории просмотров аккаунта Google.
|
• Заменить домен: Настройка истории просмотров аккаунта Google.
|
||||||
|
@ -130,7 +130,7 @@
|
|||||||
<!-- PreferenceScreen: General -->
|
<!-- PreferenceScreen: General -->
|
||||||
<string name="revanced_preference_screen_general_title">Загальні</string>
|
<string name="revanced_preference_screen_general_title">Загальні</string>
|
||||||
<string name="revanced_change_start_page_title">Змінити початкову сторінку</string>
|
<string name="revanced_change_start_page_title">Змінити початкову сторінку</string>
|
||||||
<string name="revanced_change_start_page_summary">Виберіть сторінку з якої буде стартувати додаток.</string>
|
<string name="revanced_change_start_page_summary">Виберіть сторінку з якої буде стартувати застосунок.</string>
|
||||||
<string name="revanced_change_start_page_entry_default">За замовчуванням</string>
|
<string name="revanced_change_start_page_entry_default">За замовчуванням</string>
|
||||||
<string name="revanced_change_start_page_entry_charts">Хіт-паради</string>
|
<string name="revanced_change_start_page_entry_charts">Хіт-паради</string>
|
||||||
<string name="revanced_change_start_page_entry_episodes_for_later">Послухати пізніше</string>
|
<string name="revanced_change_start_page_entry_episodes_for_later">Послухати пізніше</string>
|
||||||
@ -183,13 +183,13 @@
|
|||||||
<string name="revanced_remove_viewer_discretion_dialog_title">Вилучити діалог про небажаний контент</string>
|
<string name="revanced_remove_viewer_discretion_dialog_title">Вилучити діалог про небажаний контент</string>
|
||||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"Вилучає діалог про небажаний контент.
|
<string name="revanced_remove_viewer_discretion_dialog_summary">"Вилучає діалог про небажаний контент.
|
||||||
Це не обходить вікові обмеження. Просто приймає їх автоматично."</string>
|
Це не обходить вікові обмеження. Просто приймає їх автоматично."</string>
|
||||||
<string name="revanced_spoof_app_version_title">Підробити версію програми</string>
|
<string name="revanced_spoof_app_version_title">Підмінити версію програми</string>
|
||||||
<string name="revanced_spoof_app_version_summary">"Підміна версії клієнта на старішу версію.
|
<string name="revanced_spoof_app_version_summary">"Підміняє версію клієнта на старішу версію.
|
||||||
|
|
||||||
• Це змінить зовнішній вигляд програми, але можуть виникнути невідомі побічні ефекти.
|
• Це змінить зовнішній вигляд застосунку, але можуть виникнути невідомі побічні ефекти.
|
||||||
• Якщо пізніше вимкнути, старий інтерфейс може залишитися, доки не буде очищено дані програми."</string>
|
• Якщо пізніше вимкнути, старий інтерфейс може залишитися, доки не буде очищено дані застосунку."</string>
|
||||||
<string name="revanced_spoof_app_version_target_title">Підробити цільову версію програми</string>
|
<string name="revanced_spoof_app_version_target_title">Підмінити цільову версію застосунку</string>
|
||||||
<string name="revanced_spoof_app_version_target_summary">Виберіть зі списку цільову версію підробки програми.</string>
|
<string name="revanced_spoof_app_version_target_summary">Виберіть зі списку цільову версію для підміни.</string>
|
||||||
<string name="revanced_spoof_app_version_target_entry_6_42_55">6.42.55 - Вимкнення динамічних текстів</string>
|
<string name="revanced_spoof_app_version_target_entry_6_42_55">6.42.55 - Вимкнення динамічних текстів</string>
|
||||||
<string name="revanced_spoof_app_version_target_entry_7_16_53">7.16.53 - Відновлення старої панелі дій</string>
|
<string name="revanced_spoof_app_version_target_entry_7_16_53">7.16.53 - Відновлення старої панелі дій</string>
|
||||||
<!-- PreferenceScreen: Navigation bar -->
|
<!-- PreferenceScreen: Navigation bar -->
|
||||||
@ -213,6 +213,17 @@
|
|||||||
<string name="revanced_hide_navigation_bar_summary">Приховує панель навігації.</string>
|
<string name="revanced_hide_navigation_bar_summary">Приховує панель навігації.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Приховати підписи кнопок навігації</string>
|
<string name="revanced_hide_navigation_label_title">Приховати підписи кнопок навігації</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Приховує підпис під кожною навігаційною кнопкою.</string>
|
<string name="revanced_hide_navigation_label_summary">Приховує підпис під кожною навігаційною кнопкою.</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">Заміна кнопки \"Семпли\"</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">Замінює кнопку \"Семпли\" на кнопку \"Пошук\".</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">Заміна кнопки \"Оновити\"</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">Замінює кнопку \"Оновити\" на кнопку \"Налаштування\".</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">Про заміну кнопки</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"Ця функція є експериментальною.
|
||||||
|
Існують структурні обмеження патчу, оскільки такі Activities, як Пошук і Налаштування в YouTube Music, не є загальнодоступними.
|
||||||
|
Відомі проблеми:
|
||||||
|
• Коли замінені Activity як Пошук і Налаштування закрито, відкривається початкова сторінка.
|
||||||
|
|
||||||
|
Натисніть, щоб відкрити \"Змінити початкову сторінку\"."</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Плеєр</string>
|
<string name="revanced_preference_screen_player_title">Плеєр</string>
|
||||||
<string name="revanced_add_miniplayer_next_button_title">Додати кнопку наступне у мініплеєр</string>
|
<string name="revanced_add_miniplayer_next_button_title">Додати кнопку наступне у мініплеєр</string>
|
||||||
@ -226,11 +237,11 @@
|
|||||||
<string name="revanced_custom_player_background_color_primary_title">Основний колір фону плеєра</string>
|
<string name="revanced_custom_player_background_color_primary_title">Основний колір фону плеєра</string>
|
||||||
<string name="revanced_custom_player_background_color_primary_summary">"Введіть hex код основного кольору фону плеєра.
|
<string name="revanced_custom_player_background_color_primary_summary">"Введіть hex код основного кольору фону плеєра.
|
||||||
|
|
||||||
По можливості використовуйте темні кольори, оскільки програма не підтримує світлі теми."</string>
|
По можливості використовуйте темні кольори, оскільки застосунок не підтримує світлі теми."</string>
|
||||||
<string name="revanced_custom_player_background_color_secondary_title">Вторинний колір фону плеєра</string>
|
<string name="revanced_custom_player_background_color_secondary_title">Вторинний колір фону плеєра</string>
|
||||||
<string name="revanced_custom_player_background_color_secondary_summary">"Введіть hex код вторинного кольору фону плеєра.
|
<string name="revanced_custom_player_background_color_secondary_summary">"Введіть hex код вторинного кольору фону плеєра.
|
||||||
|
|
||||||
По можливості використовуйте темні кольори, оскільки програма не підтримує світлі теми."</string>
|
По можливості використовуйте темні кольори, оскільки застосунок не підтримує світлі теми."</string>
|
||||||
<string name="revanced_custom_player_background_invalid_toast">Недійсний колір фону плеєра.</string>
|
<string name="revanced_custom_player_background_invalid_toast">Недійсний колір фону плеєра.</string>
|
||||||
<string name="revanced_change_seekbar_position_title">Змінити положення панелі прогресу</string>
|
<string name="revanced_change_seekbar_position_title">Змінити положення панелі прогресу</string>
|
||||||
<string name="revanced_change_seekbar_position_summary">Переміщує панель прогресу під кнопку відтворення.</string>
|
<string name="revanced_change_seekbar_position_summary">Переміщує панель прогресу під кнопку відтворення.</string>
|
||||||
@ -445,14 +456,19 @@
|
|||||||
• Це буде корисно лише для користувачів, які користуються дуже старими клієнтами."</string>
|
• Це буде корисно лише для користувачів, які користуються дуже старими клієнтами."</string>
|
||||||
<string name="revanced_sanitize_sharing_links_title">Обробляти поширення посилань</string>
|
<string name="revanced_sanitize_sharing_links_title">Обробляти поширення посилань</string>
|
||||||
<string name="revanced_sanitize_sharing_links_summary">Видаляє параметри запиту відстеження з посилання перед тим, як поділитися ним.</string>
|
<string name="revanced_sanitize_sharing_links_summary">Видаляє параметри запиту відстеження з посилання перед тим, як поділитися ним.</string>
|
||||||
<string name="revanced_spoof_client_title">Підміна клієнта</string>
|
<string name="revanced_spoof_client_title">Підмінити клієнт</string>
|
||||||
<string name="revanced_spoof_client_summary">Підміна клієнта щоб запобігти проблемам відтворення.</string>
|
<string name="revanced_spoof_client_summary">Підмінює клієнт, щоб запобігти проблемам із відтворенням.</string>
|
||||||
<string name="revanced_spoof_client_type_title">Клієнт за замовчуванням</string>
|
<string name="revanced_spoof_client_type_title">Клієнт за замовчуванням</string>
|
||||||
<string name="revanced_spoof_client_type_summary">Визначає клієнт за замовчуванням для підробки.</string>
|
<string name="revanced_spoof_client_type_summary">Визначає клієнт за замовчуванням для підробки.</string>
|
||||||
<string name="revanced_spoof_client_type_entry_android_music_4_27">Android Music 4.27.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_4_27">Android Music 4.27.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">Підмінити параметр плеєра</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"Підмінює параметр плеєра, щоб запобігти проблемам із відтворенням.
|
||||||
|
|
||||||
|
Побічний ефект:
|
||||||
|
• Іноді субтитри розташовані у верхній частині плеєра, а не внизу."</string>
|
||||||
<string name="revanced_watch_history_type_title">Тип історії перегляду</string>
|
<string name="revanced_watch_history_type_title">Тип історії перегляду</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• Оригінальний: Відповідає налаштуванням історії переглядів облікового запису Google, але історія переглядів може не працювати через DNS або VPN.
|
<string name="revanced_watch_history_type_summary">"• Оригінальний: Відповідає налаштуванням історії переглядів облікового запису Google, але історія переглядів може не працювати через DNS або VPN.
|
||||||
• Замінити домен: Дотримується налаштувань історії переглядів облікового запису Google.
|
• Замінити домен: Дотримується налаштувань історії переглядів облікового запису Google.
|
||||||
@ -470,7 +486,7 @@
|
|||||||
|
|
||||||
Дотримуйтесь посібника \"Don't kill my app\" для вашого пристрою і застосуйте інструкції для встановлення GmsCore.
|
Дотримуйтесь посібника \"Don't kill my app\" для вашого пристрою і застосуйте інструкції для встановлення GmsCore.
|
||||||
|
|
||||||
Це необхідно для того, щоб програма працювала."</string>
|
Це необхідно для того, щоб застосунок працював."</string>
|
||||||
<string name="gms_core_dialog_open_website_text">Відкрити сайт</string>
|
<string name="gms_core_dialog_open_website_text">Відкрити сайт</string>
|
||||||
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"Необхідно вимкнути оптимізацію енергії для MicroG GmsCore, щоб запобігти проблемам.
|
<string name="gms_core_dialog_not_whitelisted_using_battery_optimizations_message">"Необхідно вимкнути оптимізацію енергії для MicroG GmsCore, щоб запобігти проблемам.
|
||||||
|
|
||||||
|
@ -212,6 +212,18 @@ Hạn chế:
|
|||||||
<string name="revanced_hide_navigation_bar_summary">Ẩn thanh điều hướng.</string>
|
<string name="revanced_hide_navigation_bar_summary">Ẩn thanh điều hướng.</string>
|
||||||
<string name="revanced_hide_navigation_label_title">Ẩn tên bên dưới nút</string>
|
<string name="revanced_hide_navigation_label_title">Ẩn tên bên dưới nút</string>
|
||||||
<string name="revanced_hide_navigation_label_summary">Ẩn tên bên dưới các nút trên thanh điều hướng.</string>
|
<string name="revanced_hide_navigation_label_summary">Ẩn tên bên dưới các nút trên thanh điều hướng.</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_title">Thay thế nút Đoạn nhạc</string>
|
||||||
|
<string name="revanced_replace_navigation_samples_button_summary">Thay thế nút Đoạn nhạc bằng nút Tìm kiếm.</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_title">Thay thế nút Nâng cấp</string>
|
||||||
|
<string name="revanced_replace_navigation_upgrade_button_summary">Thay thế nút Nâng cấp bằng nút Cài đặt.</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_title">Về tính năng thay thế nút</string>
|
||||||
|
<string name="revanced_replace_navigation_button_about_summary">"Hiện tính năng này đang trong giai đoạn thử nghiệm.
|
||||||
|
Bản vá có một số hạn chế về mặt cấu trúc vì các hoạt động như Tìm kiếm và Cài đặt trong YouTube Music không được công khai.
|
||||||
|
|
||||||
|
Các sự cố đã biết:
|
||||||
|
• Khi một hoạt động thay thế như Tìm kiếm và Cài đặt bị đóng, trang khởi động sẽ được mở.
|
||||||
|
|
||||||
|
Bạn có thể mở Thay đổi cài đặt trang khởi động bằng cách nhấp vào đây."</string>
|
||||||
<!-- PreferenceScreen: Player -->
|
<!-- PreferenceScreen: Player -->
|
||||||
<string name="revanced_preference_screen_player_title">Trình phát</string>
|
<string name="revanced_preference_screen_player_title">Trình phát</string>
|
||||||
<string name="revanced_add_miniplayer_next_button_title">Nút tiếp theo trong trình phát thu nhỏ</string>
|
<string name="revanced_add_miniplayer_next_button_title">Nút tiếp theo trong trình phát thu nhỏ</string>
|
||||||
@ -452,6 +464,11 @@ Chi tiết:
|
|||||||
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
<string name="revanced_spoof_client_type_entry_android_music_5_29">Android Music 5.29.53</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_6_21">iOS Music 6.21</string>
|
||||||
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
<string name="revanced_spoof_client_type_entry_ios_music_7_04">iOS Music 7.04</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_title">Giả mạo thông số trình phát</string>
|
||||||
|
<string name="revanced_spoof_player_parameter_summary">"Giả mạo thông số trình phát để khắc phục sự cố phát.
|
||||||
|
|
||||||
|
Hạn chế:
|
||||||
|
• Đôi khi phụ đề hiển thị ở phía trên của trình phát thay vì ở phía dưới như thường lệ."</string>
|
||||||
<string name="revanced_watch_history_type_title">Kiểu nhật ký</string>
|
<string name="revanced_watch_history_type_title">Kiểu nhật ký</string>
|
||||||
<string name="revanced_watch_history_type_summary">"• Gốc: Tuân theo cài đặt nhật ký xem của tài khoản Google, nhưng có thể không hoạt động do DNS hoặc VPN.
|
<string name="revanced_watch_history_type_summary">"• Gốc: Tuân theo cài đặt nhật ký xem của tài khoản Google, nhưng có thể không hoạt động do DNS hoặc VPN.
|
||||||
• Thay thế miền: Vẫn tuân theo cài đặt nhật ký xem của tài khoản Google.
|
• Thay thế miền: Vẫn tuân theo cài đặt nhật ký xem của tài khoản Google.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user