mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-04-29 22:24:31 +02:00
Compare commits
40 Commits
v5.6.2-dev
...
revanced-e
Author | SHA1 | Date | |
---|---|---|---|
![]() |
42cc8201f5 | ||
![]() |
15d0fafcf8 | ||
![]() |
db10e410d3 | ||
![]() |
8f23d76f37 | ||
![]() |
7168e49121 | ||
![]() |
2b52380294 | ||
![]() |
0cc693961a | ||
![]() |
bbf863c630 | ||
![]() |
783e366242 | ||
![]() |
4a19a960c5 | ||
![]() |
e55fd4eb74 | ||
![]() |
64af7fd8b6 | ||
![]() |
457dbfec6c | ||
![]() |
22b98336d5 | ||
![]() |
7e4a71b385 | ||
![]() |
bb5964ce98 | ||
![]() |
15db05c636 | ||
![]() |
3f9edca15d | ||
![]() |
bb1498df76 | ||
![]() |
26bf2f4b82 | ||
![]() |
ae69aca189 | ||
![]() |
8d84304737 | ||
![]() |
1926becdfc | ||
![]() |
9146d9283b | ||
![]() |
8db38af44f | ||
![]() |
1aaf03df50 | ||
![]() |
ee0a7b5443 | ||
![]() |
a9408b0f51 | ||
![]() |
03c0826fab | ||
![]() |
0384907324 | ||
![]() |
2b0f12cb9e | ||
![]() |
5088daa434 | ||
![]() |
b5fe136898 | ||
![]() |
807494f8a7 | ||
![]() |
d8ae741853 | ||
![]() |
934c33a0f9 | ||
![]() |
b725e54aee | ||
![]() |
c57de97576 | ||
![]() |
2e3274152b | ||
![]() |
6499b7d3f0 |
28
README.md
28
README.md
@ -134,19 +134,19 @@ See the [documentation](https://github.com/inotia00/revanced-documentation#readm
|
||||
|
||||
| 💊 Patch | 📜 Description | 🏹 Target Version |
|
||||
|:--------:|:--------------:|:-----------------:|
|
||||
| `Change package name` | Changes the package name for Reddit to the name specified in patch options. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Custom branding name for Reddit` | Changes the Reddit app name to the name specified in patch options. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Disable screenshot popup` | Adds an option to disable the popup that appears when taking a screenshot. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Hide Recently Visited shelf` | Adds an option to hide the Recently Visited shelf in the sidebar. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Hide ads` | Adds options to hide ads. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Hide navigation buttons` | Adds options to hide buttons in the navigation bar. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Hide recommended communities shelf` | Adds an option to hide the recommended communities shelves in subreddits. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Open links directly` | Adds an option to skip over redirection URLs in external links. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Open links externally` | Adds an option to always open links in your browser instead of in the in-app-browser. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Premium icon` | Unlocks premium app icons. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Remove subreddit dialog` | Adds options to remove the NSFW community warning and notifications suggestion dialogs by dismissing them automatically. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Sanitize sharing links` | Adds an option to sanitize sharing links by removing tracking query parameters. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Settings for Reddit` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 2024.17.0 ~ 2025.12.0 |
|
||||
| `Change package name` | Changes the package name for Reddit to the name specified in patch options. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Custom branding name for Reddit` | Changes the Reddit app name to the name specified in patch options. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Disable screenshot popup` | Adds an option to disable the popup that appears when taking a screenshot. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Hide Recently Visited shelf` | Adds an option to hide the Recently Visited shelf in the sidebar. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Hide ads` | Adds options to hide ads. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Hide navigation buttons` | Adds options to hide buttons in the navigation bar. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Hide recommended communities shelf` | Adds an option to hide the recommended communities shelves in subreddits. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Open links directly` | Adds an option to skip over redirection URLs in external links. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Open links externally` | Adds an option to always open links in your browser instead of in the in-app-browser. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Premium icon` | Unlocks premium app icons. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Remove subreddit dialog` | Adds options to remove the NSFW community warning and notifications suggestion dialogs by dismissing them automatically. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Sanitize sharing links` | Adds an option to sanitize sharing links by removing tracking query parameters. | 2024.17.0 ~ 2025.12.1 |
|
||||
| `Settings for Reddit` | Applies mandatory patches to implement ReVanced Extended settings into the application. | 2024.17.0 ~ 2025.12.1 |
|
||||
</details>
|
||||
|
||||
|
||||
@ -200,7 +200,7 @@ Example:
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
|
@ -33,6 +33,10 @@ public class RemoveSubRedditDialogPatch {
|
||||
clickViewDelayed(cancelButtonView);
|
||||
}
|
||||
|
||||
public static boolean spoofHasBeenVisitedStatus(boolean hasBeenVisited) {
|
||||
return Settings.REMOVE_NSFW_DIALOG.get() || hasBeenVisited;
|
||||
}
|
||||
|
||||
public static void dismissNSFWDialog(Object customDialog) {
|
||||
if (Settings.REMOVE_NSFW_DIALOG.get() &&
|
||||
customDialog instanceof Dialog dialog) {
|
||||
|
@ -5,7 +5,7 @@ import app.revanced.extension.reddit.settings.Settings;
|
||||
@SuppressWarnings("unused")
|
||||
public class ScreenshotPopupPatch {
|
||||
|
||||
public static boolean disableScreenshotPopup() {
|
||||
return Settings.DISABLE_SCREENSHOT_POPUP.get();
|
||||
public static Boolean disableScreenshotPopup(Boolean original) {
|
||||
return Settings.DISABLE_SCREENSHOT_POPUP.get() ? Boolean.FALSE : original;
|
||||
}
|
||||
}
|
||||
|
@ -183,8 +183,8 @@ public class PlayerPatch {
|
||||
// The type of descriptionView can be either ViewGroup or TextView. (A/B tests)
|
||||
// If the type of descriptionView is TextView, longer delay is required.
|
||||
final long delayMillis = descriptionView instanceof TextView
|
||||
? 500
|
||||
: 100;
|
||||
? 750
|
||||
: 200;
|
||||
|
||||
Utils.runOnMainThreadDelayed(() -> Utils.clickView(descriptionView), delayMillis);
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
package app.revanced.extension.youtube.patches.utils;
|
||||
|
||||
import static app.revanced.extension.shared.utils.StringRef.str;
|
||||
import static app.revanced.extension.shared.utils.Utils.runOnMainThreadDelayed;
|
||||
import static app.revanced.extension.youtube.utils.VideoUtils.dismissPlayer;
|
||||
import static app.revanced.extension.youtube.utils.VideoUtils.launchVideoExternalDownloader;
|
||||
import static app.revanced.extension.youtube.utils.VideoUtils.openPlaylist;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.KeyEvent;
|
||||
@ -32,30 +36,18 @@ import app.revanced.extension.youtube.patches.utils.requests.SavePlaylistRequest
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
import app.revanced.extension.youtube.shared.PlayerType;
|
||||
import app.revanced.extension.youtube.shared.VideoInformation;
|
||||
import app.revanced.extension.youtube.utils.AuthUtils;
|
||||
import app.revanced.extension.youtube.utils.ExtendedUtils;
|
||||
import app.revanced.extension.youtube.utils.VideoUtils;
|
||||
import kotlin.Pair;
|
||||
|
||||
// TODO: Implement sync queue and clean up code.
|
||||
@SuppressWarnings({"unused", "StaticFieldLeak"})
|
||||
public class PlaylistPatch extends VideoUtils {
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
private static final String[] REQUEST_HEADER_KEYS = {
|
||||
AUTHORIZATION_HEADER,
|
||||
"X-GOOG-API-FORMAT-VERSION",
|
||||
"X-Goog-Visitor-Id"
|
||||
};
|
||||
public class PlaylistPatch extends AuthUtils {
|
||||
private static final boolean QUEUE_MANAGER =
|
||||
Settings.OVERLAY_BUTTON_EXTERNAL_DOWNLOADER_QUEUE_MANAGER.get()
|
||||
|| Settings.OVERRIDE_VIDEO_DOWNLOAD_BUTTON_QUEUE_MANAGER.get();
|
||||
|
||||
private static Context mContext;
|
||||
private static volatile String authorization = "";
|
||||
public static volatile String dataSyncId = "";
|
||||
public static volatile boolean isIncognito = false;
|
||||
private static volatile Map<String, String> requestHeader;
|
||||
private static volatile String playlistId = "";
|
||||
private static volatile String videoId = "";
|
||||
|
||||
private static String checkFailedAuth;
|
||||
private static String checkFailedPlaylistId;
|
||||
@ -141,30 +133,6 @@ public class PlaylistPatch extends VideoUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void setRequestHeaders(String url, Map<String, String> requestHeaders) {
|
||||
if (QUEUE_MANAGER) {
|
||||
try {
|
||||
// Save requestHeaders whenever an account is switched.
|
||||
String auth = requestHeaders.get(AUTHORIZATION_HEADER);
|
||||
if (auth == null || authorization.equals(auth)) {
|
||||
return;
|
||||
}
|
||||
for (String key : REQUEST_HEADER_KEYS) {
|
||||
if (requestHeaders.get(key) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
authorization = auth;
|
||||
requestHeader = requestHeaders;
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "setRequestHeaders failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked by extension.
|
||||
*/
|
||||
|
@ -3,10 +3,14 @@ package app.revanced.extension.youtube.patches.video;
|
||||
import static app.revanced.extension.shared.utils.StringRef.str;
|
||||
import static app.revanced.extension.youtube.shared.RootView.isShortsActive;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.shared.settings.BooleanSetting;
|
||||
import app.revanced.extension.shared.settings.FloatSetting;
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
@ -28,48 +32,61 @@ public class PlaybackSpeedPatch {
|
||||
Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC.get();
|
||||
private static final long TOAST_DELAY_MILLISECONDS = 750;
|
||||
private static long lastTimeSpeedChanged;
|
||||
|
||||
/**
|
||||
* The last used playback speed.
|
||||
* This value is used when the default playback speed is 'Auto'.
|
||||
*/
|
||||
private static float lastSelectedPlaybackSpeed = 1.0f;
|
||||
private static float lastSelectedShortsPlaybackSpeed = 1.0f;
|
||||
|
||||
private static volatile String channelId = "";
|
||||
private static volatile String videoId = "";
|
||||
private static boolean isLiveStream;
|
||||
/**
|
||||
* The last regular video id.
|
||||
*/
|
||||
private static String videoId = "";
|
||||
|
||||
private static volatile String channelIdShorts = "";
|
||||
private static volatile String videoIdShorts = "";
|
||||
private static boolean isLiveStreamShorts;
|
||||
@GuardedBy("itself")
|
||||
private static final Map<String, Float> ignoredPlaybackSpeedVideoIds = new LinkedHashMap<>() {
|
||||
private static final int NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK = 3;
|
||||
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry eldest) {
|
||||
return size() > NUMBER_OF_LAST_VIDEO_IDS_TO_TRACK;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* This method is used to reset the playback speed to 1.0 when a general video is started, whether it is a live stream, music, or whitelist.
|
||||
*/
|
||||
public static void newVideoStarted(@NonNull String newlyLoadedChannelId, @NonNull String newlyLoadedChannelName,
|
||||
@NonNull String newlyLoadedVideoId, @NonNull String newlyLoadedVideoTitle,
|
||||
final long newlyLoadedVideoLength, boolean newlyLoadedLiveStreamValue) {
|
||||
if (isShortsActive()) {
|
||||
channelIdShorts = newlyLoadedChannelId;
|
||||
videoIdShorts = newlyLoadedVideoId;
|
||||
isLiveStreamShorts = newlyLoadedLiveStreamValue;
|
||||
|
||||
Logger.printDebug(() -> "newVideoStarted: " + newlyLoadedVideoId);
|
||||
} else {
|
||||
channelId = newlyLoadedChannelId;
|
||||
videoId = newlyLoadedVideoId;
|
||||
isLiveStream = newlyLoadedLiveStreamValue;
|
||||
|
||||
Logger.printDebug(() -> "newShortsVideoStarted: " + newlyLoadedVideoId);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (videoId.equals(newlyLoadedVideoId)) {
|
||||
return;
|
||||
}
|
||||
videoId = newlyLoadedVideoId;
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void newShortsVideoStarted(@NonNull String newlyLoadedChannelId, @NonNull String newlyLoadedChannelName,
|
||||
@NonNull String newlyLoadedVideoId, @NonNull String newlyLoadedVideoTitle,
|
||||
final long newlyLoadedVideoLength, boolean newlyLoadedLiveStreamValue) {
|
||||
channelIdShorts = newlyLoadedChannelId;
|
||||
videoIdShorts = newlyLoadedVideoId;
|
||||
isLiveStreamShorts = newlyLoadedLiveStreamValue;
|
||||
boolean isMusic = isMusic(newlyLoadedVideoId);
|
||||
boolean isWhitelisted = Whitelist.isChannelWhitelistedPlaybackSpeed(newlyLoadedVideoId);
|
||||
|
||||
Logger.printDebug(() -> "newShortsVideoStarted: " + newlyLoadedVideoId);
|
||||
if (newlyLoadedLiveStreamValue || isMusic || isWhitelisted) {
|
||||
synchronized(ignoredPlaybackSpeedVideoIds) {
|
||||
if (!ignoredPlaybackSpeedVideoIds.containsKey(newlyLoadedVideoId)) {
|
||||
lastSelectedPlaybackSpeed = 1.0f;
|
||||
ignoredPlaybackSpeedVideoIds.put(newlyLoadedVideoId, lastSelectedPlaybackSpeed);
|
||||
|
||||
VideoInformation.setPlaybackSpeed(lastSelectedPlaybackSpeed);
|
||||
VideoInformation.overridePlaybackSpeed(lastSelectedPlaybackSpeed);
|
||||
|
||||
Logger.printDebug(() -> "changing playback speed to: 1.0, isLiveStream: " + newlyLoadedLiveStreamValue +
|
||||
", isMusic: " + isMusic + ", isWhitelisted: " + isWhitelisted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,32 +115,29 @@ public class PlaybackSpeedPatch {
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* This method is called every second for regular videos and Shorts.
|
||||
*/
|
||||
public static float getPlaybackSpeed(float playbackSpeed) {
|
||||
boolean isShorts = isShortsActive();
|
||||
String currentChannelId = isShorts ? channelIdShorts : channelId;
|
||||
String currentVideoId = isShorts ? videoIdShorts : videoId;
|
||||
boolean currentVideoIsLiveStream = isShorts ? isLiveStreamShorts : isLiveStream;
|
||||
boolean currentVideoIsWhitelisted = Whitelist.isChannelWhitelistedPlaybackSpeed(currentChannelId);
|
||||
boolean currentVideoIsMusic = !isShorts && isMusic();
|
||||
|
||||
if (currentVideoIsLiveStream || currentVideoIsWhitelisted || currentVideoIsMusic) {
|
||||
Logger.printDebug(() -> "changing playback speed to: 1.0");
|
||||
VideoInformation.setPlaybackSpeed(1.0f);
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float defaultPlaybackSpeed = isShorts ? DEFAULT_PLAYBACK_SPEED_SHORTS.get() : DEFAULT_PLAYBACK_SPEED.get();
|
||||
|
||||
if (defaultPlaybackSpeed < 0) {
|
||||
float finalPlaybackSpeed = isShorts ? playbackSpeed : lastSelectedPlaybackSpeed;
|
||||
if (defaultPlaybackSpeed < 0) { // If the default playback speed is 'Auto', it will be overridden to the last used playback speed.
|
||||
float finalPlaybackSpeed = isShorts ? lastSelectedShortsPlaybackSpeed : lastSelectedPlaybackSpeed;
|
||||
VideoInformation.overridePlaybackSpeed(finalPlaybackSpeed);
|
||||
Logger.printDebug(() -> "changing playback speed to: " + finalPlaybackSpeed);
|
||||
return finalPlaybackSpeed;
|
||||
} else {
|
||||
if (isShorts) {
|
||||
VideoInformation.setPlaybackSpeed(defaultPlaybackSpeed);
|
||||
} else { // Otherwise the default playback speed is used.
|
||||
synchronized (ignoredPlaybackSpeedVideoIds) {
|
||||
if (isShorts) {
|
||||
// For Shorts, the VideoInformation.overridePlaybackSpeed() method is not used, so manually save the playback speed in VideoInformation.
|
||||
VideoInformation.setPlaybackSpeed(defaultPlaybackSpeed);
|
||||
} else if (ignoredPlaybackSpeedVideoIds.containsKey(videoId)) {
|
||||
// For general videos, check whether the default video playback speed should not be applied.
|
||||
Logger.printDebug(() -> "changing playback speed to: 1.0");
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.printDebug(() -> "changing playback speed to: " + defaultPlaybackSpeed);
|
||||
return defaultPlaybackSpeed;
|
||||
}
|
||||
@ -138,6 +152,19 @@ public class PlaybackSpeedPatch {
|
||||
public static void userSelectedPlaybackSpeed(float playbackSpeed) {
|
||||
try {
|
||||
boolean isShorts = isShortsActive();
|
||||
|
||||
// Saves the user-selected playback speed in the method.
|
||||
if (isShorts) {
|
||||
lastSelectedShortsPlaybackSpeed = playbackSpeed;
|
||||
} else {
|
||||
lastSelectedPlaybackSpeed = playbackSpeed;
|
||||
// If the user has manually changed the playback speed, the whitelist has already been applied.
|
||||
// If there is a videoId on the map, it will be removed.
|
||||
synchronized (ignoredPlaybackSpeedVideoIds) {
|
||||
ignoredPlaybackSpeedVideoIds.remove(videoId);
|
||||
}
|
||||
}
|
||||
|
||||
if (PatchStatus.RememberPlaybackSpeed()) {
|
||||
BooleanSetting rememberPlaybackSpeedLastSelectedSetting = isShorts
|
||||
? Settings.REMEMBER_PLAYBACK_SPEED_SHORTS_LAST_SELECTED
|
||||
@ -178,15 +205,23 @@ public class PlaybackSpeedPatch {
|
||||
}
|
||||
}, TOAST_DELAY_MILLISECONDS);
|
||||
}
|
||||
} else if (!isShorts) {
|
||||
lastSelectedPlaybackSpeed = playbackSpeed;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "userSelectedPlaybackSpeed failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMusic() {
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void onDismiss() {
|
||||
synchronized (ignoredPlaybackSpeedVideoIds) {
|
||||
ignoredPlaybackSpeedVideoIds.remove(videoId);
|
||||
videoId = "";
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isMusic(String videoId) {
|
||||
if (DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC && !videoId.isEmpty()) {
|
||||
try {
|
||||
MusicRequest request = MusicRequest.getRequestForVideoId(videoId);
|
||||
|
@ -0,0 +1,40 @@
|
||||
package app.revanced.extension.youtube.utils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class AuthUtils {
|
||||
public static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
public static final String[] REQUEST_HEADER_KEYS = {
|
||||
AUTHORIZATION_HEADER,
|
||||
"X-GOOG-API-FORMAT-VERSION",
|
||||
"X-Goog-Visitor-Id"
|
||||
};
|
||||
public static volatile String authorization = "";
|
||||
public static volatile String dataSyncId = "";
|
||||
public static volatile boolean isIncognito = false;
|
||||
public static volatile Map<String, String> requestHeader;
|
||||
public static volatile String playlistId = "";
|
||||
public static volatile String videoId = "";
|
||||
|
||||
public static void setRequestHeaders(String url, Map<String, String> requestHeaders) {
|
||||
try {
|
||||
// Save requestHeaders whenever an account is switched.
|
||||
String auth = requestHeaders.get(AUTHORIZATION_HEADER);
|
||||
if (auth == null || authorization.equals(auth)) {
|
||||
return;
|
||||
}
|
||||
for (String key : REQUEST_HEADER_KEYS) {
|
||||
if (requestHeaders.get(key) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
authorization = auth;
|
||||
requestHeader = requestHeaders;
|
||||
} catch (Exception ex) {
|
||||
Logger.initializationException(AuthUtils.class, "setRequestHeaders failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,5 +4,5 @@ org.gradle.parallel = true
|
||||
android.useAndroidX = true
|
||||
kotlin.code.style = official
|
||||
kotlin.jvm.target.validation.mode = IGNORE
|
||||
version = 5.6.2-dev.1
|
||||
version = 5.6.2
|
||||
|
||||
|
50
patches.json
50
patches.json
@ -188,7 +188,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": [
|
||||
@ -485,7 +485,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": [
|
||||
@ -1024,14 +1024,13 @@
|
||||
"description": "Adds an option to disable the popup that appears when taking a screenshot.",
|
||||
"use": true,
|
||||
"dependencies": [
|
||||
"Settings for Reddit",
|
||||
"ResourcePatch"
|
||||
"Settings for Reddit"
|
||||
],
|
||||
"compatiblePackages": {
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -1310,6 +1309,15 @@
|
||||
"Clone": "com.rvx.android.apps.youtube.music",
|
||||
"Default": "app.rvx.android.apps.youtube.music"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "patchAllManifest",
|
||||
"title": "Patch all manifest components",
|
||||
"description": "Patch all permissions, intents and content provider authorities supported by GmsCore.",
|
||||
"required": true,
|
||||
"type": "kotlin.Boolean",
|
||||
"default": true,
|
||||
"values": null
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1374,6 +1382,15 @@
|
||||
"Clone": "com.rvx.android.apps.youtube.music",
|
||||
"Default": "app.rvx.android.apps.youtube.music"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "patchAllManifest",
|
||||
"title": "Patch all manifest components",
|
||||
"description": "Patch all permissions, intents and content provider authorities supported by GmsCore.",
|
||||
"required": true,
|
||||
"type": "kotlin.Boolean",
|
||||
"default": true,
|
||||
"values": null
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -1388,7 +1405,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -1537,7 +1554,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -1689,7 +1706,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -1790,7 +1807,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -1988,7 +2005,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -2005,7 +2022,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -2161,7 +2178,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -2219,7 +2236,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -2405,7 +2422,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": []
|
||||
@ -2465,7 +2482,7 @@
|
||||
"com.reddit.frontpage": [
|
||||
"2024.17.0",
|
||||
"2025.05.1",
|
||||
"2025.12.0"
|
||||
"2025.12.1"
|
||||
]
|
||||
},
|
||||
"options": [
|
||||
@ -2510,7 +2527,7 @@
|
||||
"description": "The settings menu name that the RVX settings menu should be above.",
|
||||
"required": true,
|
||||
"type": "kotlin.String",
|
||||
"default": "@string/about_key",
|
||||
"default": "@string/parent_tools_key",
|
||||
"values": {
|
||||
"Parent settings": "@string/parent_tools_key",
|
||||
"General": "@string/general_key",
|
||||
@ -3097,6 +3114,7 @@
|
||||
"BytecodePatch",
|
||||
"BytecodePatch",
|
||||
"BytecodePatch",
|
||||
"BytecodePatch",
|
||||
"ResourcePatch"
|
||||
],
|
||||
"compatiblePackages": {
|
||||
|
@ -414,7 +414,7 @@ public final class app/revanced/patches/reddit/layout/screenshotpopup/Screenshot
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/layout/subredditdialog/FingerprintsKt {
|
||||
public static final fun indexOfGetOverInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;)I
|
||||
public static final fun indexOfHasBeenVisitedInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;)I
|
||||
public static final fun indexOfSetBackgroundTintListInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;)I
|
||||
public static final fun listOfIsLoggedInInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;)Ljava/util/List;
|
||||
}
|
||||
@ -459,9 +459,7 @@ public final class app/revanced/patches/reddit/utils/extension/SharedExtensionPa
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/utils/resourceid/SharedResourceIdPatchKt {
|
||||
public static final fun getActionShare ()J
|
||||
public static final fun getNsfwDialogTitle ()J
|
||||
public static final fun getScreenShotShareBanner ()J
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/reddit/utils/settings/SettingsPatchKt {
|
||||
@ -897,6 +895,10 @@ public final class app/revanced/patches/youtube/utils/FingerprintsKt {
|
||||
public static final fun indexOfSpannedCharSequenceInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;)I
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/utils/auth/AuthHookPatchKt {
|
||||
public static final fun getAuthHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
||||
public final class app/revanced/patches/youtube/utils/bottomsheet/BottomSheetHookPatchKt {
|
||||
public static final fun getBottomSheetHookPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
|
||||
}
|
||||
|
@ -1,60 +0,0 @@
|
||||
package app.revanced.patches.reddit.layout.screenshotpopup
|
||||
|
||||
import app.revanced.patches.reddit.utils.resourceid.actionShare
|
||||
import app.revanced.patches.reddit.utils.resourceid.screenShotShareBanner
|
||||
import app.revanced.util.containsLiteralInstruction
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
import app.revanced.util.or
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val screenshotBannerContainerFingerprint = legacyFingerprint(
|
||||
name = "screenshotTakenBannerFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
strings = listOf(
|
||||
"bannerContainer",
|
||||
"scope",
|
||||
)
|
||||
)
|
||||
|
||||
/**
|
||||
* Reddit 2025.06.0 ~
|
||||
*/
|
||||
internal val screenshotTakenBannerComposableFingerprint = legacyFingerprint(
|
||||
name = "screenshotTakenBannerComposableFingerprint",
|
||||
returnType = "L",
|
||||
customFingerprint = { method, classDef ->
|
||||
method.containsLiteralInstruction(actionShare) &&
|
||||
method.containsLiteralInstruction(screenShotShareBanner) &&
|
||||
classDef.type.startsWith("Lcom/reddit/sharing/screenshot/composables/") &&
|
||||
method.name == "invoke"
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* ~ Reddit 2025.05.1
|
||||
*/
|
||||
internal val screenshotTakenBannerLambdaActionFingerprint = legacyFingerprint(
|
||||
name = "screenshotTakenBannerLambdaFingerprint",
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroidx/compose/runtime/", "I"),
|
||||
customFingerprint = { method, _ ->
|
||||
method.containsLiteralInstruction(actionShare) &&
|
||||
method.name == "invoke"
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* ~ Reddit 2025.05.1
|
||||
*/
|
||||
internal val screenshotTakenBannerLambdaBannerFingerprint = legacyFingerprint(
|
||||
name = "screenshotTakenBannerLambdaFingerprint",
|
||||
returnType = "V",
|
||||
parameters = listOf("Landroidx/compose/runtime/", "I"),
|
||||
customFingerprint = { method, _ ->
|
||||
method.containsLiteralInstruction(screenShotShareBanner) &&
|
||||
method.name == "invoke"
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -1,37 +1,23 @@
|
||||
package app.revanced.patches.reddit.layout.screenshotpopup
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
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.patch.PatchList.DISABLE_SCREENSHOT_POPUP
|
||||
import app.revanced.patches.reddit.utils.resourceid.actionShare
|
||||
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.updatePatchStatus
|
||||
import app.revanced.util.findMutableMethodOf
|
||||
import app.revanced.util.fingerprint.methodCall
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstruction
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
private const val EXTENSION_METHOD_DESCRIPTOR =
|
||||
"$PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup()Z"
|
||||
|
||||
@Suppress("unused")
|
||||
val screenshotPopupPatch = bytecodePatch(
|
||||
DISABLE_SCREENSHOT_POPUP.title,
|
||||
@ -39,75 +25,61 @@ val screenshotPopupPatch = bytecodePatch(
|
||||
) {
|
||||
compatibleWith(COMPATIBLE_PACKAGE)
|
||||
|
||||
dependsOn(
|
||||
settingsPatch,
|
||||
sharedResourceIdPatch,
|
||||
)
|
||||
dependsOn(settingsPatch)
|
||||
|
||||
execute {
|
||||
|
||||
val screenshotTriggerSharingListenerMethodCall =
|
||||
screenshotBannerContainerFingerprint.methodCall()
|
||||
|
||||
fun indexOfScreenshotTriggerInstruction(method: Method) =
|
||||
fun indexOfShowBannerInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
getReference<MethodReference>()?.toString() == screenshotTriggerSharingListenerMethodCall
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
reference?.name?.contains("shouldShowBanner") == true &&
|
||||
reference.definingClass.startsWith("Lcom/reddit/sharing/screenshot/") == true
|
||||
}
|
||||
|
||||
val isScreenshotTriggerMethod: Method.() -> Boolean = {
|
||||
indexOfScreenshotTriggerInstruction(this) >= 0
|
||||
fun indexOfSetValueInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
getReference<MethodReference>()?.name == "setValue"
|
||||
}
|
||||
|
||||
fun indexOfBooleanInstruction(method: Method, startIndex: Int = 0) =
|
||||
method.indexOfFirstInstruction(startIndex) {
|
||||
val reference = getReference<FieldReference>()
|
||||
opcode == Opcode.SGET_OBJECT &&
|
||||
reference?.definingClass == "Ljava/lang/Boolean;" &&
|
||||
reference.type == "Ljava/lang/Boolean;"
|
||||
}
|
||||
|
||||
val isScreenShotMethod: Method.() -> Boolean = {
|
||||
definingClass.startsWith("Lcom/reddit/sharing/screenshot/") &&
|
||||
name == "invokeSuspend" &&
|
||||
indexOfShowBannerInstruction(this) >= 0 &&
|
||||
indexOfBooleanInstruction(this) >= 0 &&
|
||||
indexOfSetValueInstruction(this) >= 0
|
||||
}
|
||||
|
||||
var hookCount = 0
|
||||
|
||||
fun MutableMethod.hook() {
|
||||
if (returnType == "V") {
|
||||
addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
|
||||
move-result v0
|
||||
if-eqz v0, :shown
|
||||
return-void
|
||||
""", ExternalLabel("shown", getInstruction(0))
|
||||
)
|
||||
|
||||
hookCount++
|
||||
} else if (returnType.startsWith("L")) { // Reddit 2025.06+
|
||||
val insertIndex =
|
||||
indexOfFirstStringInstruction("screenshotTriggerSharingListener")
|
||||
|
||||
if (insertIndex >= 0) {
|
||||
val insertRegister =
|
||||
getInstruction<OneRegisterInstruction>(insertIndex).registerA
|
||||
val triggerIndex =
|
||||
indexOfScreenshotTriggerInstruction(this)
|
||||
val jumpIndex =
|
||||
indexOfFirstInstructionOrThrow(triggerIndex, Opcode.RETURN_OBJECT)
|
||||
|
||||
addInstructionsWithLabels(
|
||||
insertIndex, """
|
||||
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
|
||||
move-result v$insertRegister
|
||||
if-nez v$insertRegister, :hidden
|
||||
""", ExternalLabel("hidden", getInstruction(jumpIndex))
|
||||
)
|
||||
|
||||
hookCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
screenshotBannerContainerFingerprint
|
||||
.methodOrThrow()
|
||||
.hook()
|
||||
|
||||
classes.forEach { classDef ->
|
||||
classDef.methods.forEach { method ->
|
||||
if (method.isScreenshotTriggerMethod()) {
|
||||
if (method.isScreenShotMethod()) {
|
||||
proxy(classDef)
|
||||
.mutableClass
|
||||
.findMutableMethodOf(method)
|
||||
.hook()
|
||||
.apply {
|
||||
val showBannerIndex = indexOfShowBannerInstruction(this)
|
||||
val booleanIndex = indexOfBooleanInstruction(this, showBannerIndex)
|
||||
val booleanRegister =
|
||||
getInstruction<OneRegisterInstruction>(booleanIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
booleanIndex + 1, """
|
||||
invoke-static {v$booleanRegister}, $PATCHES_PATH/ScreenshotPopupPatch;->disableScreenshotPopup(Ljava/lang/Boolean;)Ljava/lang/Boolean;
|
||||
move-result-object v$booleanRegister
|
||||
"""
|
||||
)
|
||||
hookCount++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,44 +88,6 @@ val screenshotPopupPatch = bytecodePatch(
|
||||
throw PatchException("Failed to find hook method")
|
||||
}
|
||||
|
||||
if (is_2025_06_or_greater) {
|
||||
screenshotTakenBannerComposableFingerprint.methodOrThrow().apply {
|
||||
arrayOf(
|
||||
actionShare,
|
||||
screenShotShareBanner
|
||||
).forEach { literal ->
|
||||
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literal)
|
||||
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 {
|
||||
arrayOf(
|
||||
screenshotTakenBannerLambdaActionFingerprint,
|
||||
screenshotTakenBannerLambdaBannerFingerprint
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.methodOrThrow().addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $EXTENSION_METHOD_DESCRIPTOR
|
||||
move-result v0
|
||||
if-eqz v0, :ignore
|
||||
return-void
|
||||
:ignore
|
||||
nop
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
updatePatchStatus(
|
||||
"enableScreenshotPopup",
|
||||
DISABLE_SCREENSHOT_POPUP
|
||||
|
@ -10,7 +10,6 @@ import com.android.tools.smali.dexlib2.Opcode
|
||||
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.TypeReference
|
||||
|
||||
internal val frequentUpdatesSheetScreenFingerprint = legacyFingerprint(
|
||||
name = "frequentUpdatesSheetScreenFingerprint",
|
||||
@ -54,13 +53,6 @@ fun listOfIsLoggedInInstruction(method: Method) =
|
||||
?.reversed()
|
||||
?: emptyList()
|
||||
|
||||
fun indexOfGetOverInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.name == "getOver18"
|
||||
}
|
||||
|
||||
internal val nsfwAlertEmitFingerprint = legacyFingerprint(
|
||||
name = "nsfwAlertEmitFingerprint",
|
||||
returnType = "Ljava/lang/Object;",
|
||||
@ -68,24 +60,17 @@ internal val nsfwAlertEmitFingerprint = legacyFingerprint(
|
||||
strings = listOf("reddit://reddit/r/", "nsfwAlertDelegate"),
|
||||
customFingerprint = { method, _ ->
|
||||
method.name == "emit" &&
|
||||
indexOfGetOverInstruction(method) >= 0
|
||||
indexOfHasBeenVisitedInstruction(method) >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal val nsfwAlertObserverFingerprint = legacyFingerprint(
|
||||
name = "nsfwAlertObserverFingerprint",
|
||||
returnType = "Ljava/lang/Object;",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
strings = listOf("nsfwAlertDelegate"),
|
||||
customFingerprint = { method, _ ->
|
||||
method.name == "invokeSuspend" &&
|
||||
indexOfGetOverInstruction(method) >= 0 &&
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.NEW_INSTANCE &&
|
||||
getReference<TypeReference>()?.type?.startsWith("Lcom/reddit/frontpage/presentation/detail/DetailHolderPresenter\$showDialogIfNeverVisitedOrSubscribed\$") == true
|
||||
} >= 0
|
||||
fun indexOfHasBeenVisitedInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.name == "getHasBeenVisited" &&
|
||||
reference.returnType == "Z"
|
||||
}
|
||||
)
|
||||
|
||||
internal val nsfwAlertBuilderFingerprint = legacyFingerprint(
|
||||
name = "nsfwAlertBuilderFingerprint",
|
||||
|
@ -2,11 +2,9 @@ package app.revanced.patches.reddit.layout.subredditdialog
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
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.patch.PatchList.REMOVE_SUBREDDIT_DIALOG
|
||||
@ -17,7 +15,6 @@ import app.revanced.patches.reddit.utils.settings.is_2025_05_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.updatePatchStatus
|
||||
import app.revanced.util.findFreeRegister
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.fingerprint.mutableClassOrThrow
|
||||
import app.revanced.util.getReference
|
||||
@ -80,26 +77,17 @@ val subRedditDialogPatch = bytecodePatch(
|
||||
}
|
||||
|
||||
if (is_2025_01_or_greater) {
|
||||
arrayOf(
|
||||
nsfwAlertEmitFingerprint,
|
||||
nsfwAlertObserverFingerprint
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.methodOrThrow().apply {
|
||||
val getOverIndex = indexOfGetOverInstruction(this)
|
||||
val getOverRegister = getInstruction<FiveRegisterInstruction>(getOverIndex).registerC
|
||||
val freeRegister = findFreeRegister(getOverIndex, getOverRegister)
|
||||
nsfwAlertEmitFingerprint.methodOrThrow().apply {
|
||||
val hasBeenVisitedIndex = indexOfHasBeenVisitedInstruction(this)
|
||||
val hasBeenVisitedRegister =
|
||||
getInstruction<OneRegisterInstruction>(hasBeenVisitedIndex + 1).registerA
|
||||
|
||||
val returnIndex = indexOfFirstInstructionOrThrow(getOverIndex, Opcode.RETURN_OBJECT)
|
||||
val jumpIndex = indexOfFirstInstructionReversedOrThrow(returnIndex, Opcode.SGET_OBJECT)
|
||||
|
||||
addInstructionsWithLabels(
|
||||
getOverIndex, """
|
||||
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->removeNSFWDialog()Z
|
||||
move-result v$freeRegister
|
||||
if-nez v$freeRegister, :jump
|
||||
""", ExternalLabel("jump", getInstruction(jumpIndex))
|
||||
)
|
||||
}
|
||||
addInstructions(
|
||||
hasBeenVisitedIndex + 2, """
|
||||
invoke-static {v$hasBeenVisitedRegister}, $EXTENSION_CLASS_DESCRIPTOR->spoofHasBeenVisitedStatus(Z)Z
|
||||
move-result v$hasBeenVisitedRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
var hookCount = 0
|
||||
|
@ -11,7 +11,7 @@ internal object Constants {
|
||||
setOf(
|
||||
"2024.17.0", // This is the last version that can be patched without anti-split.
|
||||
"2025.05.1", // This was the latest version supported by the previous RVX patch.
|
||||
"2025.12.0", // This is the latest version supported by the RVX patch.
|
||||
"2025.12.1", // This is the latest version supported by the RVX patch.
|
||||
)
|
||||
)
|
||||
}
|
@ -5,12 +5,8 @@ import app.revanced.patches.shared.mapping.ResourceType.STRING
|
||||
import app.revanced.patches.shared.mapping.getResourceId
|
||||
import app.revanced.patches.shared.mapping.resourceMappingPatch
|
||||
|
||||
var actionShare = -1L
|
||||
private set
|
||||
var nsfwDialogTitle = -1L
|
||||
private set
|
||||
var screenShotShareBanner = -1L
|
||||
private set
|
||||
|
||||
internal val sharedResourceIdPatch = resourcePatch(
|
||||
description = "sharedResourceIdPatch"
|
||||
@ -18,8 +14,6 @@ internal val sharedResourceIdPatch = resourcePatch(
|
||||
dependsOn(resourceMappingPatch)
|
||||
|
||||
execute {
|
||||
actionShare = getResourceId(STRING, "action_share")
|
||||
nsfwDialogTitle = getResourceId(STRING, "nsfw_dialog_title")
|
||||
screenShotShareBanner = getResourceId(STRING, "screenshot_share_banner_title")
|
||||
}
|
||||
}
|
@ -106,3 +106,8 @@ internal val primesLifecycleEventFingerprint = legacyFingerprint(
|
||||
} >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal val primeMethodFingerprint = legacyFingerprint(
|
||||
name = "primesLifecycleEventFingerprint",
|
||||
strings = listOf("com.google.android.GoogleCamera", "com.android.vending")
|
||||
)
|
@ -4,6 +4,7 @@ import app.revanced.patcher.Fingerprint
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.instructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatchBuilder
|
||||
import app.revanced.patcher.patch.BytecodePatchContext
|
||||
@ -18,9 +19,13 @@ import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patcher.patch.stringOption
|
||||
import app.revanced.patches.shared.extension.Constants.PATCHES_PATH
|
||||
import app.revanced.patches.shared.gms.Constants.ACTIONS
|
||||
import app.revanced.patches.shared.gms.Constants.ACTIONS_LEGACY
|
||||
import app.revanced.patches.shared.gms.Constants.AUTHORITIES
|
||||
import app.revanced.patches.shared.gms.Constants.AUTHORITIES_LEGACY
|
||||
import app.revanced.patches.shared.gms.Constants.PERMISSIONS
|
||||
import app.revanced.patches.shared.gms.Constants.PERMISSIONS_LEGACY
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.util.fingerprint.methodOrNull
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.fingerprint.mutableClassOrThrow
|
||||
import app.revanced.util.getReference
|
||||
@ -127,6 +132,14 @@ fun gmsCoreSupportPatch(
|
||||
required = true
|
||||
) { it!!.matches(Regex(PACKAGE_NAME_REGEX_PATTERN)) && it != ORIGINAL_PACKAGE_NAME_YOUTUBE_MUSIC }
|
||||
|
||||
val patchAllManifest by booleanOption(
|
||||
key = "patchAllManifest",
|
||||
default = true,
|
||||
title = "Patch all manifest components",
|
||||
description = "Patch all permissions, intents and content provider authorities supported by GmsCore.",
|
||||
required = true,
|
||||
)
|
||||
|
||||
dependsOn(
|
||||
gmsCoreSupportResourcePatchFactory(
|
||||
gmsCoreVendorGroupIdOption,
|
||||
@ -139,6 +152,20 @@ fun gmsCoreSupportPatch(
|
||||
val gmsCoreVendorGroupId by gmsCoreVendorGroupIdOption
|
||||
|
||||
execute {
|
||||
val patchAllManifestEnabled = patchAllManifest == true
|
||||
val permissions = if (patchAllManifestEnabled)
|
||||
PERMISSIONS
|
||||
else
|
||||
PERMISSIONS_LEGACY
|
||||
val actions = if (patchAllManifestEnabled)
|
||||
ACTIONS
|
||||
else
|
||||
ACTIONS_LEGACY
|
||||
val authorities = if (patchAllManifestEnabled)
|
||||
AUTHORITIES
|
||||
else
|
||||
AUTHORITIES_LEGACY
|
||||
|
||||
fun transformStringReferences(transform: (str: String) -> String?) = classes.forEach {
|
||||
val mutableClass by lazy {
|
||||
proxy(it).mutableClass
|
||||
@ -182,9 +209,9 @@ fun gmsCoreSupportPatch(
|
||||
when (referencedString) {
|
||||
"com.google",
|
||||
"com.google.android.gms",
|
||||
in PERMISSIONS,
|
||||
in ACTIONS,
|
||||
in AUTHORITIES,
|
||||
in permissions,
|
||||
in actions,
|
||||
in authorities,
|
||||
-> referencedString.replace("com.google", gmsCoreVendorGroupId!!)
|
||||
|
||||
// TODO: Add this permission when bumping GmsCore
|
||||
@ -196,7 +223,7 @@ fun gmsCoreSupportPatch(
|
||||
// only when content:// uri
|
||||
if (str.startsWith("content://")) {
|
||||
// check if matches any authority
|
||||
for (authority in AUTHORITIES) {
|
||||
for (authority in authorities) {
|
||||
val uriPrefix = "content://$authority"
|
||||
if (str.startsWith(uriPrefix)) {
|
||||
return str.replace(
|
||||
@ -223,40 +250,56 @@ fun gmsCoreSupportPatch(
|
||||
}
|
||||
}
|
||||
|
||||
fun transformPrimeMethod() {
|
||||
setOf(
|
||||
primesBackgroundInitializationFingerprint,
|
||||
primesLifecycleEventFingerprint
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.methodOrThrow().apply {
|
||||
val exceptionIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
opcode == Opcode.NEW_INSTANCE &&
|
||||
(this as? ReferenceInstruction)?.reference?.toString() == "Ljava/lang/IllegalStateException;"
|
||||
fun transformPrimeMethod(packageName: String) {
|
||||
if (patchAllManifestEnabled) {
|
||||
primeMethodFingerprint.methodOrNull()?.apply {
|
||||
var register = 2
|
||||
|
||||
val index = instructions.indexOfFirst {
|
||||
if (it.getReference<StringReference>()?.string != fromPackageName) return@indexOfFirst false
|
||||
|
||||
register = (it as OneRegisterInstruction).registerA
|
||||
return@indexOfFirst true
|
||||
}
|
||||
val index =
|
||||
indexOfFirstInstructionReversedOrThrow(exceptionIndex, Opcode.IF_EQZ)
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
addInstruction(
|
||||
index,
|
||||
"const/4 v$register, 0x1"
|
||||
)
|
||||
|
||||
replaceInstruction(index, "const-string v$register, \"$packageName\"")
|
||||
}
|
||||
}
|
||||
primesApiFingerprint.mutableClassOrThrow().methods.filter { method ->
|
||||
method.name != "<clinit>" &&
|
||||
method.returnType == "V"
|
||||
}.forEach { method ->
|
||||
method.apply {
|
||||
val index = if (MethodUtil.isConstructor(method))
|
||||
indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
getReference<MethodReference>()?.name == "<init>"
|
||||
} + 1
|
||||
else 0
|
||||
addInstruction(
|
||||
index,
|
||||
"return-void"
|
||||
)
|
||||
} else {
|
||||
setOf(
|
||||
primesBackgroundInitializationFingerprint,
|
||||
primesLifecycleEventFingerprint
|
||||
).forEach { fingerprint ->
|
||||
fingerprint.methodOrThrow().apply {
|
||||
val exceptionIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
opcode == Opcode.NEW_INSTANCE &&
|
||||
(this as? ReferenceInstruction)?.reference?.toString() == "Ljava/lang/IllegalStateException;"
|
||||
}
|
||||
val index =
|
||||
indexOfFirstInstructionReversedOrThrow(exceptionIndex, Opcode.IF_EQZ)
|
||||
val register = getInstruction<OneRegisterInstruction>(index).registerA
|
||||
addInstruction(
|
||||
index,
|
||||
"const/4 v$register, 0x1"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
primesApiFingerprint.mutableClassOrThrow().methods.filter { method ->
|
||||
method.name != "<clinit>" &&
|
||||
method.returnType == "V"
|
||||
}.forEach { method ->
|
||||
method.apply {
|
||||
val index = if (MethodUtil.isConstructor(method))
|
||||
indexOfFirstInstructionOrThrow {
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
getReference<MethodReference>()?.name == "<init>"
|
||||
} + 1
|
||||
else 0
|
||||
addInstruction(
|
||||
index,
|
||||
"return-void"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -280,37 +323,40 @@ fun gmsCoreSupportPatch(
|
||||
return@transform null
|
||||
}
|
||||
|
||||
// Return these methods early to prevent the app from crashing.
|
||||
setOf(
|
||||
val earlyReturnFingerprints = mutableListOf(
|
||||
castContextFetchFingerprint,
|
||||
castDynamiteModuleFingerprint,
|
||||
castDynamiteModuleV2Fingerprint,
|
||||
googlePlayUtilityFingerprint,
|
||||
serviceCheckFingerprint,
|
||||
sslGuardFingerprint,
|
||||
).forEach { it.methodOrThrow().returnEarly() }
|
||||
serviceCheckFingerprint
|
||||
)
|
||||
|
||||
// Prevent spam logs.
|
||||
eCatcherFingerprint.methodOrThrow().apply {
|
||||
val index = indexOfFirstInstructionOrThrow(Opcode.NEW_ARRAY)
|
||||
addInstruction(index, "return-void")
|
||||
if (patchAllManifestEnabled) {
|
||||
earlyReturnFingerprints += listOf(sslGuardFingerprint)
|
||||
|
||||
// Prevent spam logs.
|
||||
eCatcherFingerprint.methodOrThrow().apply {
|
||||
val index = indexOfFirstInstructionOrThrow(Opcode.NEW_ARRAY)
|
||||
addInstruction(index, "return-void")
|
||||
}
|
||||
}
|
||||
|
||||
// Return these methods early to prevent the app from crashing.
|
||||
earlyReturnFingerprints.forEach { it.methodOrThrow().returnEarly() }
|
||||
|
||||
// Specific method that needs to be patched.
|
||||
transformPrimeMethod()
|
||||
transformPrimeMethod(packageName)
|
||||
|
||||
// Verify GmsCore is installed and whitelisted for power optimizations and background usage.
|
||||
mainActivityOnCreateFingerprint.method.apply {
|
||||
// Temporary fix for patches with an extension patch that hook the onCreate method as well.
|
||||
val setContextIndex = indexOfFirstInstruction {
|
||||
val reference =
|
||||
getReference<MethodReference>() ?: return@indexOfFirstInstruction false
|
||||
if (checkGmsCore == true) {
|
||||
mainActivityOnCreateFingerprint.method.apply {
|
||||
// Temporary fix for patches with an extension patch that hook the onCreate method as well.
|
||||
val setContextIndex = indexOfFirstInstruction {
|
||||
val reference =
|
||||
getReference<MethodReference>() ?: return@indexOfFirstInstruction false
|
||||
|
||||
reference.toString() == "Lapp/revanced/extension/shared/Utils;->setContext(Landroid/content/Context;)V"
|
||||
}
|
||||
reference.toString() == "Lapp/revanced/extension/shared/Utils;->setContext(Landroid/content/Context;)V"
|
||||
}
|
||||
|
||||
// Add after setContext call, because this patch needs the context.
|
||||
if (checkGmsCore == true) {
|
||||
// Add after setContext call, because this patch needs the context.
|
||||
addInstructions(
|
||||
if (setContextIndex < 0) 0 else setContextIndex + 1,
|
||||
"invoke-static/range { p0 .. p0 }, $EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
@ -335,7 +381,30 @@ fun gmsCoreSupportPatch(
|
||||
* that are present in GmsCore which need to be transformed.
|
||||
*/
|
||||
private object Constants {
|
||||
/**
|
||||
* All permissions.
|
||||
*/
|
||||
val PERMISSIONS = setOf(
|
||||
"com.google.android.c2dm.permission.RECEIVE",
|
||||
"com.google.android.c2dm.permission.SEND",
|
||||
"com.google.android.gms.auth.api.phone.permission.SEND",
|
||||
"com.google.android.gms.permission.AD_ID",
|
||||
"com.google.android.gms.permission.AD_ID_NOTIFICATION",
|
||||
"com.google.android.gms.permission.CAR_FUEL",
|
||||
"com.google.android.gms.permission.CAR_INFORMATION",
|
||||
"com.google.android.gms.permission.CAR_MILEAGE",
|
||||
"com.google.android.gms.permission.CAR_SPEED",
|
||||
"com.google.android.gms.permission.CAR_VENDOR_EXTENSION",
|
||||
"com.google.android.googleapps.permission.GOOGLE_AUTH",
|
||||
"com.google.android.googleapps.permission.GOOGLE_AUTH.cp",
|
||||
"com.google.android.googleapps.permission.GOOGLE_AUTH.local",
|
||||
"com.google.android.googleapps.permission.GOOGLE_AUTH.mail",
|
||||
"com.google.android.googleapps.permission.GOOGLE_AUTH.writely",
|
||||
"com.google.android.gtalkservice.permission.GTALK_SERVICE",
|
||||
"com.google.android.providers.gsf.permission.READ_GSERVICES",
|
||||
)
|
||||
|
||||
val PERMISSIONS_LEGACY = setOf(
|
||||
// C2DM / GCM
|
||||
"com.google.android.c2dm.permission.RECEIVE",
|
||||
"com.google.android.c2dm.permission.SEND",
|
||||
@ -349,7 +418,234 @@ private object Constants {
|
||||
// "com.google.android.gms.permission.ACTIVITY_RECOGNITION",
|
||||
)
|
||||
|
||||
/**
|
||||
* All intent actions.
|
||||
*/
|
||||
val ACTIONS = setOf(
|
||||
"com.google.android.c2dm.intent.RECEIVE",
|
||||
"com.google.android.c2dm.intent.REGISTER",
|
||||
"com.google.android.c2dm.intent.REGISTRATION",
|
||||
"com.google.android.c2dm.intent.UNREGISTER",
|
||||
"com.google.android.contextmanager.service.ContextManagerService.START",
|
||||
"com.google.android.gcm.intent.SEND",
|
||||
"com.google.android.gms.accounts.ACCOUNT_SERVICE",
|
||||
"com.google.android.gms.accountsettings.ACCOUNT_PREFERENCES_SETTINGS",
|
||||
"com.google.android.gms.accountsettings.action.BROWSE_SETTINGS",
|
||||
"com.google.android.gms.accountsettings.action.VIEW_SETTINGS",
|
||||
"com.google.android.gms.accountsettings.MY_ACCOUNT",
|
||||
"com.google.android.gms.accountsettings.PRIVACY_SETTINGS",
|
||||
"com.google.android.gms.accountsettings.SECURITY_SETTINGS",
|
||||
"com.google.android.gms.ads.gservice.START",
|
||||
"com.google.android.gms.ads.identifier.service.EVENT_ATTESTATION",
|
||||
"com.google.android.gms.ads.service.CACHE",
|
||||
"com.google.android.gms.ads.service.CONSENT_LOOKUP",
|
||||
"com.google.android.gms.ads.service.HTTP",
|
||||
"com.google.android.gms.analytics.service.START",
|
||||
"com.google.android.gms.app.settings.GoogleSettingsLink",
|
||||
"com.google.android.gms.appstate.service.START",
|
||||
"com.google.android.gms.appusage.service.START",
|
||||
"com.google.android.gms.asterism.service.START",
|
||||
"com.google.android.gms.audiomodem.service.AudioModemService.START",
|
||||
"com.google.android.gms.audit.service.START",
|
||||
"com.google.android.gms.auth.account.authapi.START",
|
||||
"com.google.android.gms.auth.account.authenticator.auto.service.START",
|
||||
"com.google.android.gms.auth.account.authenticator.chromeos.START",
|
||||
"com.google.android.gms.auth.account.authenticator.tv.service.START",
|
||||
"com.google.android.gms.auth.account.data.service.START",
|
||||
"com.google.android.gms.auth.api.credentials.PICKER",
|
||||
"com.google.android.gms.auth.api.credentials.service.START",
|
||||
"com.google.android.gms.auth.api.identity.service.authorization.START",
|
||||
"com.google.android.gms.auth.api.identity.service.credentialsaving.START",
|
||||
"com.google.android.gms.auth.api.identity.service.signin.START",
|
||||
"com.google.android.gms.auth.api.phone.service.InternalService.START",
|
||||
"com.google.android.gms.auth.api.signin.service.START",
|
||||
"com.google.android.gms.auth.be.appcert.AppCertService",
|
||||
"com.google.android.gms.auth.blockstore.service.START",
|
||||
"com.google.android.gms.auth.config.service.START",
|
||||
"com.google.android.gms.auth.cryptauth.cryptauthservice.START",
|
||||
"com.google.android.gms.auth.GOOGLE_SIGN_IN",
|
||||
"com.google.android.gms.auth.login.LOGIN",
|
||||
"com.google.android.gms.auth.proximity.devicesyncservice.START",
|
||||
"com.google.android.gms.auth.proximity.securechannelservice.START",
|
||||
"com.google.android.gms.auth.proximity.START",
|
||||
"com.google.android.gms.auth.service.START",
|
||||
"com.google.android.gms.backup.ACTION_BACKUP_SETTINGS",
|
||||
"com.google.android.gms.backup.G1_BACKUP",
|
||||
"com.google.android.gms.backup.G1_RESTORE",
|
||||
"com.google.android.gms.backup.GMS_MODULE_RESTORE",
|
||||
"com.google.android.gms.beacon.internal.IBleService.START",
|
||||
"com.google.android.gms.car.service.START",
|
||||
"com.google.android.gms.carrierauth.service.START",
|
||||
"com.google.android.gms.cast.firstparty.START",
|
||||
"com.google.android.gms.cast.remote_display.service.START",
|
||||
"com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE",
|
||||
"com.google.android.gms.cast_mirroring.service.START",
|
||||
"com.google.android.gms.checkin.BIND_TO_SERVICE",
|
||||
"com.google.android.gms.chromesync.service.START",
|
||||
"com.google.android.gms.clearcut.service.START",
|
||||
"com.google.android.gms.common.account.CHOOSE_ACCOUNT",
|
||||
"com.google.android.gms.common.download.START",
|
||||
"com.google.android.gms.common.service.START",
|
||||
"com.google.android.gms.common.telemetry.service.START",
|
||||
"com.google.android.gms.config.START",
|
||||
"com.google.android.gms.constellation.service.START",
|
||||
"com.google.android.gms.credential.manager.service.firstparty.START",
|
||||
"com.google.android.gms.deviceconnection.service.START",
|
||||
"com.google.android.gms.drive.ApiService.RESET_AFTER_BOOT",
|
||||
"com.google.android.gms.drive.ApiService.START",
|
||||
"com.google.android.gms.drive.ApiService.STOP",
|
||||
"com.google.android.gms.droidguard.service.INIT",
|
||||
"com.google.android.gms.droidguard.service.PING",
|
||||
"com.google.android.gms.droidguard.service.START",
|
||||
"com.google.android.gms.enterprise.loader.service.START",
|
||||
"com.google.android.gms.facs.cache.service.START",
|
||||
"com.google.android.gms.facs.internal.service.START",
|
||||
"com.google.android.gms.feedback.internal.IFeedbackService",
|
||||
"com.google.android.gms.fido.credentialstore.internal_service.START",
|
||||
"com.google.android.gms.fido.fido2.privileged.START",
|
||||
"com.google.android.gms.fido.fido2.regular.START",
|
||||
"com.google.android.gms.fido.fido2.zeroparty.START",
|
||||
"com.google.android.gms.fido.sourcedevice.service.START",
|
||||
"com.google.android.gms.fido.targetdevice.internal_service.START",
|
||||
"com.google.android.gms.fido.u2f.privileged.START",
|
||||
"com.google.android.gms.fido.u2f.thirdparty.START",
|
||||
"com.google.android.gms.fido.u2f.zeroparty.START",
|
||||
"com.google.android.gms.fitness.BleApi",
|
||||
"com.google.android.gms.fitness.ConfigApi",
|
||||
"com.google.android.gms.fitness.GoalsApi",
|
||||
"com.google.android.gms.fitness.GoogleFitnessService.START",
|
||||
"com.google.android.gms.fitness.HistoryApi",
|
||||
"com.google.android.gms.fitness.InternalApi",
|
||||
"com.google.android.gms.fitness.RecordingApi",
|
||||
"com.google.android.gms.fitness.SensorsApi",
|
||||
"com.google.android.gms.fitness.SessionsApi",
|
||||
"com.google.android.gms.fonts.service.START",
|
||||
"com.google.android.gms.freighter.service.START",
|
||||
"com.google.android.gms.games.internal.connect.service.START",
|
||||
"com.google.android.gms.games.PLAY_GAMES_UPGRADE",
|
||||
"com.google.android.gms.games.service.START",
|
||||
"com.google.android.gms.gass.START",
|
||||
"com.google.android.gms.gmscompliance.service.START",
|
||||
"com.google.android.gms.googlehelp.HELP",
|
||||
"com.google.android.gms.googlehelp.service.GoogleHelpService.START",
|
||||
"com.google.android.gms.growth.service.START",
|
||||
"com.google.android.gms.herrevad.services.LightweightNetworkQualityAndroidService.START",
|
||||
"com.google.android.gms.icing.INDEX_SERVICE",
|
||||
"com.google.android.gms.icing.LIGHTWEIGHT_INDEX_SERVICE",
|
||||
"com.google.android.gms.identity.service.BIND",
|
||||
"com.google.android.gms.inappreach.service.START",
|
||||
"com.google.android.gms.instantapps.START",
|
||||
"com.google.android.gms.kids.service.START",
|
||||
"com.google.android.gms.languageprofile.service.START",
|
||||
"com.google.android.gms.learning.internal.dynamitesupport.START",
|
||||
"com.google.android.gms.learning.intservice.START",
|
||||
"com.google.android.gms.learning.predictor.START",
|
||||
"com.google.android.gms.learning.trainer.START",
|
||||
"com.google.android.gms.learning.training.background.START",
|
||||
"com.google.android.gms.location.places.GeoDataApi",
|
||||
"com.google.android.gms.location.places.PlaceDetectionApi",
|
||||
"com.google.android.gms.location.places.PlacesApi",
|
||||
"com.google.android.gms.location.reporting.service.START",
|
||||
"com.google.android.gms.location.settings.LOCATION_HISTORY",
|
||||
"com.google.android.gms.location.settings.LOCATION_REPORTING_SETTINGS",
|
||||
"com.google.android.gms.locationsharing.api.START",
|
||||
"com.google.android.gms.locationsharingreporter.service.START",
|
||||
"com.google.android.gms.lockbox.service.START",
|
||||
"com.google.android.gms.matchstick.lighter.service.START",
|
||||
"com.google.android.gms.mdm.services.DeviceManagerApiService.START",
|
||||
"com.google.android.gms.mdm.services.START",
|
||||
"com.google.android.gms.mdns.service.START",
|
||||
"com.google.android.gms.measurement.START",
|
||||
"com.google.android.gms.nearby.bootstrap.service.NearbyBootstrapService.START",
|
||||
"com.google.android.gms.nearby.connection.service.START",
|
||||
"com.google.android.gms.nearby.fastpair.START",
|
||||
"com.google.android.gms.nearby.messages.service.NearbyMessagesService.START",
|
||||
"com.google.android.gms.nearby.sharing.service.NearbySharingService.START",
|
||||
"com.google.android.gms.nearby.sharing.START_SERVICE",
|
||||
"com.google.android.gms.notifications.service.START",
|
||||
"com.google.android.gms.ocr.service.internal.START",
|
||||
"com.google.android.gms.ocr.service.START",
|
||||
"com.google.android.gms.oss.licenses.service.START",
|
||||
"com.google.android.gms.payse.service.BIND",
|
||||
"com.google.android.gms.people.contactssync.service.START",
|
||||
"com.google.android.gms.people.service.START",
|
||||
"com.google.android.gms.phenotype.service.START",
|
||||
"com.google.android.gms.photos.autobackup.service.START",
|
||||
"com.google.android.gms.playlog.service.START",
|
||||
"com.google.android.gms.plus.service.default.INTENT",
|
||||
"com.google.android.gms.plus.service.image.INTENT",
|
||||
"com.google.android.gms.plus.service.internal.START",
|
||||
"com.google.android.gms.plus.service.START",
|
||||
"com.google.android.gms.potokens.service.START",
|
||||
"com.google.android.gms.pseudonymous.service.START",
|
||||
"com.google.android.gms.rcs.START",
|
||||
"com.google.android.gms.reminders.service.START",
|
||||
"com.google.android.gms.romanesco.MODULE_BACKUP_AGENT",
|
||||
"com.google.android.gms.romanesco.service.START",
|
||||
"com.google.android.gms.safetynet.service.START",
|
||||
"com.google.android.gms.scheduler.ACTION_PROXY_SCHEDULE",
|
||||
"com.google.android.gms.search.service.SEARCH_AUTH_START",
|
||||
"com.google.android.gms.semanticlocation.service.START_ODLH",
|
||||
"com.google.android.gms.sesame.service.BIND",
|
||||
"com.google.android.gms.settings.EXPOSURE_NOTIFICATION_SETTINGS",
|
||||
"com.google.android.gms.setup.auth.SecondDeviceAuth.START",
|
||||
"com.google.android.gms.signin.service.START",
|
||||
"com.google.android.gms.smartdevice.d2d.SourceDeviceService.START",
|
||||
"com.google.android.gms.smartdevice.d2d.TargetDeviceService.START",
|
||||
"com.google.android.gms.smartdevice.directtransfer.SourceDirectTransferService.START",
|
||||
"com.google.android.gms.smartdevice.directtransfer.TargetDirectTransferService.START",
|
||||
"com.google.android.gms.smartdevice.postsetup.PostSetupService.START",
|
||||
"com.google.android.gms.smartdevice.setup.accounts.AccountsService.START",
|
||||
"com.google.android.gms.smartdevice.wifi.START_WIFI_HELPER_SERVICE",
|
||||
"com.google.android.gms.social.location.activity.service.START",
|
||||
"com.google.android.gms.speech.service.START",
|
||||
"com.google.android.gms.statementservice.EXECUTE",
|
||||
"com.google.android.gms.stats.ACTION_UPLOAD_DROPBOX_ENTRIES",
|
||||
"com.google.android.gms.tapandpay.service.BIND",
|
||||
"com.google.android.gms.telephonyspam.service.START",
|
||||
"com.google.android.gms.testsupport.service.START",
|
||||
"com.google.android.gms.thunderbird.service.START",
|
||||
"com.google.android.gms.trustagent.BridgeApi.START",
|
||||
"com.google.android.gms.trustagent.StateApi.START",
|
||||
"com.google.android.gms.trustagent.trustlet.trustletmanagerservice.BIND",
|
||||
"com.google.android.gms.trustlet.bluetooth.service.BIND",
|
||||
"com.google.android.gms.trustlet.connectionlessble.service.BIND",
|
||||
"com.google.android.gms.trustlet.face.service.BIND",
|
||||
"com.google.android.gms.trustlet.nfc.service.BIND",
|
||||
"com.google.android.gms.trustlet.onbody.service.BIND",
|
||||
"com.google.android.gms.trustlet.place.service.BIND",
|
||||
"com.google.android.gms.trustlet.voiceunlock.service.BIND",
|
||||
"com.google.android.gms.udc.service.START",
|
||||
"com.google.android.gms.update.START_API_SERVICE",
|
||||
"com.google.android.gms.update.START_SERVICE",
|
||||
"com.google.android.gms.update.START_SINGLE_USER_API_SERVICE",
|
||||
"com.google.android.gms.update.START_TV_API_SERVICE",
|
||||
"com.google.android.gms.usagereporting.service.START",
|
||||
"com.google.android.gms.userlocation.service.START",
|
||||
"com.google.android.gms.vehicle.cabin.service.START",
|
||||
"com.google.android.gms.vehicle.climate.service.START",
|
||||
"com.google.android.gms.vehicle.info.service.START",
|
||||
"com.google.android.gms.wallet.service.BIND",
|
||||
"com.google.android.gms.walletp2p.service.firstparty.BIND",
|
||||
"com.google.android.gms.walletp2p.service.zeroparty.BIND",
|
||||
"com.google.android.gms.wearable.BIND",
|
||||
"com.google.android.gms.wearable.BIND_LISTENER",
|
||||
"com.google.android.gms.wearable.DATA_CHANGED",
|
||||
"com.google.android.gms.wearable.MESSAGE_RECEIVED",
|
||||
"com.google.android.gms.wearable.NODE_CHANGED",
|
||||
"com.google.android.gsf.action.GET_GLS",
|
||||
"com.google.android.location.settings.LOCATION_REPORTING_SETTINGS",
|
||||
"com.google.android.mdd.service.START",
|
||||
"com.google.android.mdh.service.listener.START",
|
||||
"com.google.android.mdh.service.START",
|
||||
"com.google.android.mobstore.service.START",
|
||||
"com.google.firebase.auth.api.gms.service.START",
|
||||
"com.google.firebase.dynamiclinks.service.START",
|
||||
"com.google.iid.TOKEN_REQUEST",
|
||||
"com.google.android.gms.location.places.ui.PICK_PLACE",
|
||||
)
|
||||
|
||||
val ACTIONS_LEGACY = setOf(
|
||||
// C2DM / GCM
|
||||
"com.google.android.c2dm.intent.REGISTER",
|
||||
"com.google.android.c2dm.intent.REGISTRATION",
|
||||
@ -407,7 +703,19 @@ private object Constants {
|
||||
"com.google.android.gms.droidguard.service.START",
|
||||
)
|
||||
|
||||
/**
|
||||
* All content provider authorities.
|
||||
*/
|
||||
val AUTHORITIES = setOf(
|
||||
"com.google.android.gms.auth.accounts",
|
||||
"com.google.android.gms.chimera",
|
||||
"com.google.android.gms.fonts",
|
||||
"com.google.android.gms.phenotype",
|
||||
"com.google.android.gsf.gservices",
|
||||
"com.google.settings",
|
||||
)
|
||||
|
||||
val AUTHORITIES_LEGACY = setOf(
|
||||
// gsf
|
||||
"com.google.android.gsf.gservices",
|
||||
|
||||
|
@ -218,8 +218,7 @@ val customBrandingIconPatch = resourcePatch(
|
||||
}
|
||||
|
||||
val styleList = mutableListOf(
|
||||
Triple(
|
||||
"values-v31",
|
||||
Pair(
|
||||
"Base.Theme.YouTube.Launcher",
|
||||
"@style/Theme.AppCompat.DayNight.NoActionBar"
|
||||
),
|
||||
@ -227,21 +226,15 @@ val customBrandingIconPatch = resourcePatch(
|
||||
|
||||
if (is_19_32_or_greater) {
|
||||
styleList += listOf(
|
||||
Triple(
|
||||
"values-night-v31",
|
||||
"Theme.YouTube.Home",
|
||||
"@style/Base.V27.Theme.YouTube.Home"
|
||||
),
|
||||
Triple(
|
||||
"values-v31",
|
||||
Pair(
|
||||
"Theme.YouTube.Home",
|
||||
"@style/Base.V27.Theme.YouTube.Home"
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
styleList.forEach { (directory, nodeAttributeName, nodeAttributeParent) ->
|
||||
document("res/$directory/styles.xml").use { document ->
|
||||
styleList.forEach { (nodeAttributeName, nodeAttributeParent) ->
|
||||
document("res/values-v31/styles.xml").use { document ->
|
||||
val resourcesNode =
|
||||
document.getElementsByTagName("resources").item(0) as Element
|
||||
|
||||
|
@ -1,41 +1,17 @@
|
||||
package app.revanced.patches.youtube.shorts.startupshortsreset
|
||||
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import app.revanced.util.or
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
/**
|
||||
* YouTube v18.15.40 ~ YouTube 19.46.42
|
||||
* YouTube v18.15.40+
|
||||
*/
|
||||
internal val userWasInShortsABConfigFingerprint = legacyFingerprint(
|
||||
internal val userWasInShortsConfigFingerprint = legacyFingerprint(
|
||||
name = "userWasInShortsABConfigFingerprint",
|
||||
returnType = "V",
|
||||
strings = listOf("Failed to get offline response: "),
|
||||
customFingerprint = { method, _ ->
|
||||
indexOfOptionalInstruction(method) >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfOptionalInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_STATIC &&
|
||||
getReference<MethodReference>().toString() == "Lj${'$'}/util/Optional;->of(Ljava/lang/Object;)Lj${'$'}/util/Optional;"
|
||||
}
|
||||
|
||||
/**
|
||||
* YouTube 19.47.53 ~
|
||||
*/
|
||||
internal val userWasInShortsABConfigAlternativeFingerprint = legacyFingerprint(
|
||||
name = "userWasInShortsABConfigAlternativeFingerprint",
|
||||
returnType = "V",
|
||||
parameters = listOf("I"),
|
||||
opcodes = listOf(Opcode.OR_INT_LIT8),
|
||||
strings = listOf("alias", "null"),
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
returnType = "Z",
|
||||
literals = listOf(45358360L)
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -4,14 +4,10 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.SHORTS_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.DISABLE_RESUMING_SHORTS_ON_STARTUP
|
||||
import app.revanced.patches.youtube.utils.playservice.is_19_46_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.is_20_02_or_greater
|
||||
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
@ -19,10 +15,8 @@ import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||
import app.revanced.util.fingerprint.matchOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstStringInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
@ -42,50 +36,19 @@ val resumingShortsOnStartupPatch = bytecodePatch(
|
||||
|
||||
execute {
|
||||
|
||||
fun MutableMethod.hookUserWasInShortsABConfig(startIndex: Int) {
|
||||
val walkerIndex = implementation!!.instructions.let {
|
||||
val subListIndex =
|
||||
it.subList(startIndex, startIndex + 20).indexOfFirst { instruction ->
|
||||
val reference = instruction.getReference<MethodReference>()
|
||||
instruction.opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.returnType == "Z" &&
|
||||
reference.definingClass != "Lj${'$'}/util/Optional;" &&
|
||||
reference.parameterTypes.isEmpty()
|
||||
}
|
||||
if (subListIndex < 0)
|
||||
throw PatchException("subListIndex not found")
|
||||
|
||||
startIndex + subListIndex
|
||||
}
|
||||
val walkerMethod = getWalkerMethod(walkerIndex)
|
||||
|
||||
// This method will only be called for the user being A/B tested.
|
||||
// Presumably a method that processes the ProtoDataStore value (boolean) for the 'user_was_in_shorts' key.
|
||||
walkerMethod.apply {
|
||||
addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $SHORTS_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z
|
||||
move-result v0
|
||||
if-eqz v0, :show
|
||||
const/4 v0, 0x0
|
||||
return v0
|
||||
""", ExternalLabel("show", getInstruction(0))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (is_19_46_or_greater) {
|
||||
userWasInShortsABConfigAlternativeFingerprint.methodOrThrow().apply {
|
||||
val stringIndex = indexOfFirstStringInstructionOrThrow("null")
|
||||
val startIndex = indexOfFirstInstructionOrThrow(stringIndex, Opcode.OR_INT_LIT8)
|
||||
hookUserWasInShortsABConfig(startIndex)
|
||||
}
|
||||
} else {
|
||||
userWasInShortsABConfigFingerprint.methodOrThrow().apply {
|
||||
val startIndex = indexOfOptionalInstruction(this)
|
||||
hookUserWasInShortsABConfig(startIndex)
|
||||
}
|
||||
}
|
||||
userWasInShortsConfigFingerprint
|
||||
.methodOrThrow()
|
||||
.addInstructionsWithLabels(
|
||||
0, """
|
||||
invoke-static {}, $SHORTS_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z
|
||||
move-result v0
|
||||
if-eqz v0, :show
|
||||
const/4 v0, 0x0
|
||||
return v0
|
||||
:show
|
||||
nop
|
||||
"""
|
||||
)
|
||||
|
||||
if (is_20_02_or_greater) {
|
||||
userWasInShortsAlternativeFingerprint.matchOrThrow().let {
|
||||
|
@ -0,0 +1,34 @@
|
||||
package app.revanced.patches.youtube.utils.auth
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.EXTENSION_PATH
|
||||
import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.utils.request.buildRequestPatch
|
||||
import app.revanced.patches.youtube.utils.request.hookBuildRequest
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
|
||||
private const val EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR =
|
||||
"$EXTENSION_PATH/utils/AuthUtils;"
|
||||
|
||||
val authHookPatch = bytecodePatch(
|
||||
description = "authHookPatch"
|
||||
) {
|
||||
dependsOn(
|
||||
sharedExtensionPatch,
|
||||
buildRequestPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
// Get incognito status and data sync id.
|
||||
accountIdentityFingerprint.methodOrThrow().addInstructions(
|
||||
1, """
|
||||
sput-object p3, $EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR->dataSyncId:Ljava/lang/String;
|
||||
sput-boolean p4, $EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR->isIncognito:Z
|
||||
"""
|
||||
)
|
||||
|
||||
// Get the header to use the auth token.
|
||||
hookBuildRequest("$EXTENSION_AUTH_UTILS_CLASS_DESCRIPTOR->setRequestHeaders(Ljava/lang/String;Ljava/util/Map;)V")
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package app.revanced.patches.youtube.utils.auth
|
||||
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
import app.revanced.util.or
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
|
||||
internal val accountIdentityFingerprint = legacyFingerprint(
|
||||
name = "accountIdentityFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
customFingerprint = { method, _ ->
|
||||
method.definingClass.endsWith("${'$'}AutoValue_AccountIdentity;")
|
||||
}
|
||||
)
|
@ -3,12 +3,14 @@ package app.revanced.patches.youtube.utils.dismiss
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.EXTENSION_PATH
|
||||
import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch
|
||||
import app.revanced.util.addStaticFieldToExtension
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getWalkerMethod
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
|
||||
@ -21,6 +23,8 @@ import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
private const val EXTENSION_VIDEO_UTILS_CLASS_DESCRIPTOR =
|
||||
"$EXTENSION_PATH/utils/VideoUtils;"
|
||||
|
||||
private lateinit var dismissMethod: MutableMethod
|
||||
|
||||
val dismissPlayerHookPatch = bytecodePatch(
|
||||
description = "dismissPlayerHookPatch"
|
||||
) {
|
||||
@ -36,6 +40,21 @@ val dismissPlayerHookPatch = bytecodePatch(
|
||||
reference?.returnType == "V" &&
|
||||
reference.parameterTypes.isEmpty()
|
||||
}
|
||||
|
||||
getWalkerMethod(dismissPlayerIndex).apply {
|
||||
val jumpIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.returnType == "V"
|
||||
}
|
||||
getWalkerMethod(jumpIndex).apply {
|
||||
val jumpIndex = indexOfFirstInstructionReversedOrThrow {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.returnType == "V"
|
||||
}
|
||||
dismissMethod = getWalkerMethod(jumpIndex)
|
||||
}
|
||||
}
|
||||
|
||||
val dismissPlayerReference =
|
||||
getInstruction<ReferenceInstruction>(dismissPlayerIndex).reference as MethodReference
|
||||
val dismissPlayerClass = dismissPlayerReference.definingClass
|
||||
@ -80,4 +99,13 @@ val dismissPlayerHookPatch = bytecodePatch(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called when the video is closed.
|
||||
*/
|
||||
internal fun hookDismissObserver(descriptor: String) =
|
||||
dismissMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static {}, $descriptor"
|
||||
)
|
@ -1,11 +1,9 @@
|
||||
package app.revanced.patches.youtube.utils.fix.splash
|
||||
|
||||
import app.revanced.patcher.patch.resourcePatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.YOUTUBE_PACKAGE_NAME
|
||||
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.settings.ResourceUtils.youtubePackageName
|
||||
import app.revanced.util.findElementByAttributeValueOrThrow
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.restoreOldSplashAnimationIncluded
|
||||
import org.w3c.dom.Element
|
||||
|
||||
/**
|
||||
@ -22,16 +20,13 @@ val darkModeSplashScreenPatch = resourcePatch(
|
||||
) {
|
||||
dependsOn(versionCheckPatch)
|
||||
|
||||
execute {
|
||||
finalize {
|
||||
if (!is_19_32_or_greater) {
|
||||
return@execute
|
||||
return@finalize
|
||||
}
|
||||
|
||||
arrayOf(
|
||||
"values-night",
|
||||
"values-night-v27",
|
||||
).forEach { directory ->
|
||||
document("res/$directory/styles.xml").use { document ->
|
||||
if (restoreOldSplashAnimationIncluded) {
|
||||
document("res/values-night/styles.xml").use { document ->
|
||||
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
||||
val childNodes = resourcesNode.childNodes
|
||||
|
||||
@ -45,38 +40,41 @@ val darkModeSplashScreenPatch = resourcePatch(
|
||||
style.setAttribute("name", "Theme.YouTube.Home")
|
||||
style.setAttribute("parent", nodeAttributeParent)
|
||||
|
||||
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 windowItem = document.createElement("item")
|
||||
windowItem.setAttribute("name", "android:windowBackground")
|
||||
windowItem.textContent = "@color/yt_black1"
|
||||
style.appendChild(windowItem)
|
||||
|
||||
resourcesNode.removeChild(node)
|
||||
resourcesNode.appendChild(style)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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")
|
||||
|
||||
finalize {
|
||||
// GmsCore support included
|
||||
if (youtubePackageName != YOUTUBE_PACKAGE_NAME) {
|
||||
document("AndroidManifest.xml").use { document ->
|
||||
val mainActivityElement = document.childNodes.findElementByAttributeValueOrThrow(
|
||||
"android:name",
|
||||
"com.google.android.apps.youtube.app.watchwhile.MainActivity",
|
||||
)
|
||||
// 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)
|
||||
}
|
||||
|
||||
mainActivityElement.setAttribute("android:launchMode", "singleTask")
|
||||
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element
|
||||
resourcesNode.appendChild(style)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,15 +9,6 @@ import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal val accountIdentityFingerprint = legacyFingerprint(
|
||||
name = "accountIdentityFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
customFingerprint = { method, _ ->
|
||||
method.definingClass.endsWith("${'$'}AutoValue_AccountIdentity;")
|
||||
}
|
||||
)
|
||||
|
||||
internal val editPlaylistConstructorFingerprint = legacyFingerprint(
|
||||
name = "editPlaylistConstructorFingerprint",
|
||||
returnType = "V",
|
||||
|
@ -7,13 +7,12 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.shared.mainactivity.getMainActivityMethod
|
||||
import app.revanced.patches.youtube.utils.auth.authHookPatch
|
||||
import app.revanced.patches.youtube.utils.dismiss.dismissPlayerHookPatch
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.UTILS_PATH
|
||||
import app.revanced.patches.youtube.utils.extension.sharedExtensionPatch
|
||||
import app.revanced.patches.youtube.utils.mainactivity.mainActivityResolvePatch
|
||||
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.request.buildRequestPatch
|
||||
import app.revanced.patches.youtube.utils.request.hookBuildRequest
|
||||
import app.revanced.patches.youtube.video.information.videoInformationPatch
|
||||
import app.revanced.util.fingerprint.matchOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
@ -34,21 +33,10 @@ val playlistPatch = bytecodePatch(
|
||||
dismissPlayerHookPatch,
|
||||
playerTypeHookPatch,
|
||||
videoInformationPatch,
|
||||
buildRequestPatch,
|
||||
authHookPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
// In Incognito mode, sending a request always seems to fail.
|
||||
accountIdentityFingerprint.methodOrThrow().addInstructions(
|
||||
1, """
|
||||
sput-object p3, $EXTENSION_CLASS_DESCRIPTOR->dataSyncId:Ljava/lang/String;
|
||||
sput-boolean p4, $EXTENSION_CLASS_DESCRIPTOR->isIncognito:Z
|
||||
"""
|
||||
)
|
||||
|
||||
// Get the header to use the auth token.
|
||||
hookBuildRequest("$EXTENSION_CLASS_DESCRIPTOR->setRequestHeaders(Ljava/lang/String;Ljava/util/Map;)V")
|
||||
|
||||
// Open the queue manager by pressing and holding the back button.
|
||||
getMainActivityMethod("onKeyLongPress")
|
||||
.addInstructionsWithLabels(
|
||||
|
@ -96,11 +96,11 @@ private val settingsBytecodePatch = bytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
private const val DEFAULT_ELEMENT = "@string/about_key"
|
||||
private const val DEFAULT_ELEMENT = "@string/parent_tools_key"
|
||||
private const val DEFAULT_LABEL = "RVX"
|
||||
|
||||
private val SETTINGS_ELEMENTS_MAP = mapOf(
|
||||
"Parent settings" to "@string/parent_tools_key",
|
||||
"Parent settings" to DEFAULT_ELEMENT,
|
||||
"General" to "@string/general_key",
|
||||
"Account" to "@string/account_switcher_key",
|
||||
"Data saving" to "@string/data_saving_settings_key",
|
||||
@ -121,7 +121,7 @@ private val SETTINGS_ELEMENTS_MAP = mapOf(
|
||||
"Live chat" to "@string/live_chat_key",
|
||||
"Captions" to "@string/captions_key",
|
||||
"Accessibility" to "@string/accessibility_settings_key",
|
||||
"About" to DEFAULT_ELEMENT
|
||||
"About" to "@string/about_key"
|
||||
)
|
||||
|
||||
private lateinit var settingsLabel: String
|
||||
|
@ -11,6 +11,8 @@ import app.revanced.patches.shared.customspeed.customPlaybackSpeedPatch
|
||||
import app.revanced.patches.shared.litho.addLithoFilter
|
||||
import app.revanced.patches.shared.litho.lithoFilterPatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.dismiss.dismissPlayerHookPatch
|
||||
import app.revanced.patches.youtube.utils.dismiss.hookDismissObserver
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.PATCH_STATUS_CLASS_DESCRIPTOR
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.VIDEO_PATH
|
||||
@ -25,7 +27,6 @@ import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.video.information.hookBackgroundPlayVideoInformation
|
||||
import app.revanced.patches.youtube.video.information.hookShortsVideoInformation
|
||||
import app.revanced.patches.youtube.video.information.hookVideoInformation
|
||||
import app.revanced.patches.youtube.video.information.onCreateHook
|
||||
import app.revanced.patches.youtube.video.information.speedSelectionInsertMethod
|
||||
@ -87,6 +88,7 @@ val videoPlaybackPatch = bytecodePatch(
|
||||
),
|
||||
flyoutMenuHookPatch,
|
||||
lithoFilterPatch,
|
||||
dismissPlayerHookPatch,
|
||||
playerTypeHookPatch,
|
||||
recyclerViewTreeObserverPatch,
|
||||
shortsPlaybackPatch,
|
||||
@ -183,9 +185,9 @@ val videoPlaybackPatch = bytecodePatch(
|
||||
}
|
||||
|
||||
hookBackgroundPlayVideoInformation("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
hookShortsVideoInformation("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newShortsVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
hookVideoInformation("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V")
|
||||
hookPlayerResponseVideoId("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->fetchMusicRequest(Ljava/lang/String;Z)V")
|
||||
hookDismissObserver("$EXTENSION_PLAYBACK_SPEED_CLASS_DESCRIPTOR->onDismiss()V")
|
||||
|
||||
updatePatchStatus(PATCH_STATUS_CLASS_DESCRIPTOR, "RememberPlaybackSpeed")
|
||||
|
||||
|
@ -183,7 +183,7 @@
|
||||
<string name="revanced_restore_old_style_library_shelf_title">이전 보관함 선반으로 복원</string>
|
||||
<string name="revanced_restore_old_style_library_shelf_summary">이전 보관함 탭으로 복원합니다. (실험 기능)</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_title">시청 경고 다이얼로그 제거</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"다음 콘텐츠를 재생하기 전에 표시되는 시청 경고 다이얼로그를 제거합니다:\n• 연령 제한 콘텐츠\n• 혐오감을 주는 콘텐츠\n• 자살 또는 자해와 관련된 콘텐츠 ...\n\n이 설정은 다이얼로그를 자동으로 허용하기만 하며 연령 제한(성인인증 절차)을 우회할 수 없습니다."</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"다음 콘텐츠를 재생하기 전에 표시되는 시청 경고 다이얼로그를 제거합니다:\n• 연령 제한 콘텐츠\n• 자살 또는 자해와 관련된 콘텐츠, etc.\n\n이 설정은 다이얼로그를 자동으로 허용하기만 하며 연령 제한(성인인증 절차)을 우회할 수 없습니다."</string>
|
||||
<string name="revanced_spoof_app_version_title">앱 버전 변경</string>
|
||||
<string name="revanced_spoof_app_version_summary">"이전 앱 버전으로 변경합니다.
|
||||
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">إضافة إلى قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">إضافة إلى قائمة الانتظار وفتح قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">إضافة إلى قائمة الانتظار وتشغيل الفيديو</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">إضافة إلى قائمة الانتظار وإعادة تحميل الفيديو</string>
|
||||
<string name="revanced_queue_manager_external_downloader">أداة التنزيل الخارجي</string>
|
||||
<string name="revanced_queue_manager_open_queue">فتح قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_queue">قائمة الإنتظار</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">إزالة من قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">إزالة من قائمة الانتظار وفتح قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">إزالة من قائمة الانتظار وإعادة تحميل الفيديو</string>
|
||||
<string name="revanced_queue_manager_remove_queue">إزالة قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_save_queue">حفظ قائمة الانتظار</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"بدلاً من فتح برنامج تنزيل خارجي، افتح نافذة مدير قائمة الانتظار.
|
||||
@ -203,18 +205,18 @@
|
||||
<string name="revanced_hide_get_premium_summary_on">تم إخفاء الترقية لـ YouTube Premium.</string>
|
||||
<string name="revanced_hide_get_premium_summary_off">يتم عرض الترقية لـ YouTube Premium.</string>
|
||||
<!-- PreferenceScreen: Alternative thumbnails -->
|
||||
<string name="revanced_preference_screen_alt_thumbnails_title">مُصغَّرات فيديو بديلة</string>
|
||||
<string name="revanced_preference_screen_alt_thumbnails_title">مصغرات فيديو بديلة</string>
|
||||
<string name="revanced_alt_thumbnail_home_title">علامة تبويب الصفحة الرئيسية</string>
|
||||
<string name="revanced_alt_thumbnail_player_title">قوائم تشغيل المشغل، التوصيات</string>
|
||||
<string name="revanced_alt_thumbnail_search_title">نتائج البحث</string>
|
||||
<string name="revanced_alt_thumbnail_subscriptions_title">علامة تبويب الاشتراكات</string>
|
||||
<string name="revanced_alt_thumbnail_library_title">علامة التبويب أنت</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_1">المصّغرات الأصلية</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow & المصّغرات الأصلية</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_1">المصغرات الأصلية</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_2">DeArrow & المصغرات الأصلية</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_3">DeArrow & اللقطات الثابتة</string>
|
||||
<string name="revanced_alt_thumbnail_options_entry_4">اللقطات الثابتة</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_about_title">DeArrow</string>
|
||||
<string name="revanced_alt_thumbnail_dearrow_about_summary">"يوفر DeArrow مُصغَّرات فيديو تم جمعها من الجمهور لفيديوهات YouTube. غالبًا ما تكون مُصغَّرات الفيديو هذه ذات صلة أكثر من تلك التي يقدمها موقع YouTube.
|
||||
<string name="revanced_alt_thumbnail_dearrow_about_summary">"يوفر DeArrow مصغرات فيديو تم جمعها من الجمهور لفيديوهات YouTube. غالبًا ما تكون مصغرات الفيديو هذه ذات صلة أكثر من تلك التي يقدمها موقع YouTube.
|
||||
|
||||
اذا تم تمكين هذا الخيار، سيتم إرسال عناوين URL للفيديو إلى خادم API ولن يتم إرسال أي بيانات أخرى. إذا لم يكن الفيديو يحتوي على مُصغَّرات لـ DeArrow، فسيتم عرض اللقطات الأصلية أو الثابتة.
|
||||
|
||||
@ -228,7 +230,7 @@
|
||||
<string name="revanced_alt_thumbnail_stills_about_title">لقطات الفيديو الثابتة</string>
|
||||
<string name="revanced_alt_thumbnail_stills_about_summary">يتم التقاط اللقطات الثابتة من بداية أو منتصف أو نهاية كل فيديو. هذه الصور مدمجة في YouTube ولا يتم استخدام أي واجهة برمجة تطبيقات خارجية.</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_title">استخدام اللقطات الثابتة السريعة</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_summary_on">استخدام اللقطات متوسطة الجودة. سيتم تحميل المُصغَّرات بشكل أسرع، ولكن البث المباشر أو المقاطع التي لم يتم إصدارها أو القديمة جدًا قد تعرض مُصغَّرات فارغة.</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_summary_on">استخدام اللقطات متوسطة الجودة. سيتم تحميل المصغرات بشكل أسرع، ولكن البث المباشر أو المقاطع التي لم يتم إصدارها أو القديمة جدًا قد تعرض مصغرات فارغة.</string>
|
||||
<string name="revanced_alt_thumbnail_stills_fast_summary_off">استخدام لقطات الفيديو الثابتة بجودة عالية.</string>
|
||||
<string name="revanced_alt_thumbnail_stills_time_title">وقت الفيديو لأخذ اللقطات الثابتة منه</string>
|
||||
<string name="revanced_alt_thumbnail_stills_time_entry_1">بداية الفيديو</string>
|
||||
@ -246,9 +248,9 @@
|
||||
<string name="revanced_hide_album_card_title">إخفاء بطاقات الألبوم</string>
|
||||
<string name="revanced_hide_album_card_summary_on">تم إخفاء بطاقات الألبوم.</string>
|
||||
<string name="revanced_hide_album_card_summary_off">يتم عرض بطاقات الألبوم.</string>
|
||||
<string name="revanced_hide_feed_captions_button_title">إخفاء زر التَرْجَمَة</string>
|
||||
<string name="revanced_hide_feed_captions_button_on">تم إخفاء زر التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_feed_captions_button_off">يتم عرض زر التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_feed_captions_button_title">إخفاء زر الترجمة</string>
|
||||
<string name="revanced_hide_feed_captions_button_on">تم إخفاء زر الترجمة.</string>
|
||||
<string name="revanced_hide_feed_captions_button_off">يتم عرض زر الترجمة.</string>
|
||||
<string name="revanced_hide_carousel_shelf_title">إخفاء الرفوف الدوارة</string>
|
||||
<string name="revanced_hide_carousel_shelf_summary_on">"تم إخفاء الرفوف الدوارة، مثل:
|
||||
• أخبار عاجلة
|
||||
@ -981,12 +983,12 @@
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_title">إخفاء قائمة المقطع الصوتي</string>
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_summary_on">تم إخفاء قائمة المقطع الصوتي.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_audio_track_summary_off">يتم عرض قائمة المقطع الصوتي.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_title">إخفاء قائمة التَرْجَمَة</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_summary_on">تم إخفاء قائمة التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_summary_off">يتم عرض قائمة التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_footer_title">إخفاء تذييل قائمة التَرْجَمَة</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_footer_summary_on">تم إخفاء تذييل قائمة التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_footer_summary_off">يتم عرض تذييل قائمة التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_title">إخفاء قائمة الترجمة</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_summary_on">تم إخفاء قائمة الترجمة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_summary_off">يتم عرض قائمة الترجمة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_footer_title">إخفاء تذييل قائمة الترجمة</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_footer_summary_on">تم إخفاء تذييل قائمة الترجمة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_captions_footer_summary_off">يتم عرض تذييل قائمة الترجمة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_lock_screen_title">إخفاء قائمة قفل الشاشة</string>
|
||||
<string name="revanced_hide_player_flyout_menu_lock_screen_summary_on">تم إخفاء قائمة قفل الشاشة.</string>
|
||||
<string name="revanced_hide_player_flyout_menu_lock_screen_summary_off">يتم عرض قائمة قفل الشاشة.</string>
|
||||
@ -1191,9 +1193,9 @@
|
||||
<string name="revanced_hide_player_autoplay_button_title">إخفاء زر التشغيل التلقائي</string>
|
||||
<string name="revanced_hide_player_autoplay_button_summary_on">تم إخفاء زر التشغيل التلقائي.</string>
|
||||
<string name="revanced_hide_player_autoplay_button_summary_off">يتم عرض زر التشغيل التلقائي.</string>
|
||||
<string name="revanced_hide_player_captions_button_title">إخفاء زر التَرْجَمَة</string>
|
||||
<string name="revanced_hide_player_captions_button_summary_on">تم إخفاء زر التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_player_captions_button_summary_off">يتم عرض زر التَرْجَمَة.</string>
|
||||
<string name="revanced_hide_player_captions_button_title">إخفاء زر الترجمة</string>
|
||||
<string name="revanced_hide_player_captions_button_summary_on">تم إخفاء زر الترجمة.</string>
|
||||
<string name="revanced_hide_player_captions_button_summary_off">يتم عرض زر الترجمة.</string>
|
||||
<string name="revanced_hide_player_cast_button_title">إخفاء زر البث</string>
|
||||
<string name="revanced_hide_player_cast_button_summary_on">تم إخفاء زر البث.</string>
|
||||
<string name="revanced_hide_player_cast_button_summary_off">يتم عرض زر البث.</string>
|
||||
@ -1637,9 +1639,7 @@
|
||||
<string name="revanced_swipe_overlay_rect_size_summary">النسبة المئوية لمساحة الشاشة القابلة للتمرير السريع.\n\nملاحظة: سيؤدي هذا أيضًا إلى تغيير حجم مساحة الشاشة لإيماءة النقر المزدوج للتقديم أو التأخير.</string>
|
||||
<string name="revanced_swipe_overlay_rect_size_invalid_toast">لا يمكن أن يزيد حجم المنطقة القابلة للتمرير السريع عن 50.</string>
|
||||
<string name="revanced_swipe_overlay_timeout_title">مهلة واجهة إيماءة التمرير</string>
|
||||
<string name="revanced_swipe_overlay_timeout_summary">مقدار الوقت الذي تظهر فيه واجهة التمرير بعد التغيير (بجزء الثانية).
|
||||
|
||||
الافتراضي:500</string>
|
||||
<string name="revanced_swipe_overlay_timeout_summary">أجزاء الثانية التي تكون فيها الواجهة مرئية.</string>
|
||||
<string name="revanced_swipe_brightness_sensitivity_title">حساسية تمرير مستوى السطوع</string>
|
||||
<string name="revanced_swipe_brightness_sensitivity_summary">تكوين الحد الأدنى للمسافة لتمرير السطوع بين 1 و1000 (%).\nكلما كانت المسافة الدنيا أقصر، كلما تغيرت مستويات السطوع بشكل أسرع.</string>
|
||||
<string name="revanced_swipe_brightness_sensitivity_invalid_toast">يجب أن تكون حساسية تمرير مستوى السطوع بين 1-1000 (%).</string>
|
||||
@ -1817,7 +1817,7 @@
|
||||
<!-- PreferenceScreen: SponsorBlock -->
|
||||
<string name="revanced_preference_screen_sb_title">SponsorBlock</string>
|
||||
<string name="revanced_sb_enable_sb">تمكين SponsorBlock</string>
|
||||
<string name="revanced_sb_enable_sb_sum">SponsorBlock مانِع الرُعَاة هو نظام جماعي لتخطي الأجزاء المزعجة من فيديوهات YouTube.</string>
|
||||
<string name="revanced_sb_enable_sb_sum">مانِع الرُعَاة هو نظام جماعي لتخطي الأجزاء المزعجة من فيديوهات YouTube.</string>
|
||||
<!-- PreferenceScreen: SponsorBlock, PreferenceCategory: Appearance -->
|
||||
<string name="revanced_sb_appearance_category">المظهر</string>
|
||||
<string name="revanced_sb_enable_voting">عرض زر التصويت</string>
|
||||
@ -1905,7 +1905,7 @@
|
||||
<string name="revanced_sb_enable_create_segment_sum_on">يتم عرض زر إنشاء مقطع جديد.</string>
|
||||
<string name="revanced_sb_enable_create_segment_sum_off">لا يتم عرض زر إنشاء مقطع جديد.</string>
|
||||
<string name="revanced_sb_general_adjusting">تعديل تقديم او تأخير المقطع الجديد</string>
|
||||
<string name="revanced_sb_general_adjusting_sum">أجزاء الثانية في الوقت الذي تتحرك فيها أزرار ضبط الوقت عند إنشاء مقاطع جديدة.</string>
|
||||
<string name="revanced_sb_general_adjusting_sum">أجزاء الثانية في الوقت الذي تتحرك فيه أزرار ضبط الوقت عند إنشاء مقاطع جديدة.</string>
|
||||
<string name="revanced_sb_general_adjusting_invalid">يجب أن تكون القيمة رقمًا موجبًا.</string>
|
||||
<string name="revanced_sb_guidelines_preference_title">عرض الإرشادات</string>
|
||||
<string name="revanced_sb_guidelines_preference_sum">الإرشادات تحتوي على نصائح حول تقديم المقاطع.</string>
|
||||
@ -2155,6 +2155,10 @@ AVC لديه حد أقصى للدقة 1080p، لا يتوفر ترميز الص
|
||||
<string name="revanced_preference_screen_patch_information_title">معلومات التعديل</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">معلومات عن التعديلات المطبقة.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">معلومات التطبيق</string>
|
||||
<string name="revanced_app_name_title">اسم التطبيق</string>
|
||||
<string name="revanced_app_version_title">إصدار التطبيق</string>
|
||||
<string name="revanced_patched_date_title">تاريخ التعديل</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">أخرى</string>
|
||||
<string name="revanced_icon_custom">مخصص</string>
|
||||
|
@ -22,11 +22,13 @@ Bitte lade %2$s von der Webseite herunter."</string>
|
||||
<string name="revanced_queue_manager_add_to_queue">Zur Warteschlange hinzufügen</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Zur Warteschlange hinzufügen & öffnen</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Zur Warteschlange hinzufügen und Video abspielen</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Zur Warteschlange hinzufügen und Video neu laden</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Externer Downloader</string>
|
||||
<string name="revanced_queue_manager_open_queue">Warteschlange öffnen</string>
|
||||
<string name="revanced_queue_manager_queue">Warteschlange</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Aus der Warteschlange entfernen</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Aus der Warteschlange entfernen und die Warteschlange öffnen</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Aus der Warteschlange entfernen und Video neu laden</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Warteschlange löschen</string>
|
||||
<string name="revanced_queue_manager_save_queue">Warteschlange speichern</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Öffnen Sie statt eines externen Downloaders den Warteschlangenmanager.
|
||||
@ -113,7 +115,7 @@ Bitte verwenden Sie sie nur zu Debugging-Zwecken."</string>
|
||||
<string name="revanced_language_ZH">""</string>
|
||||
<!-- PreferenceScreen: Ads -->
|
||||
<string name="revanced_preference_screen_ads_title">Werbung</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Endbild-Banner ausblenden</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Abspann Store Banner ausblenden</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_on">Store-Banner ist ausgeblendet.</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_summary_off">Store-Banner wird angezeigt.</string>
|
||||
<string name="revanced_hide_fullscreen_ads_title">Vollbildwerbung verstecken</string>
|
||||
@ -791,7 +793,7 @@ Information:
|
||||
|
||||
Autoplay kann in den YouTube-Einstellungen geändert werden:
|
||||
Einstellungen → Autoplay → Nächstes Video automatisch abspielen"</string>
|
||||
<string name="revanced_hide_suggested_video_end_screen_summary_off">Empfohlene Video-Endbildschirm wird angezeigt.</string>
|
||||
<string name="revanced_hide_suggested_video_end_screen_summary_off">Empfohlene Videos Endbildschirm wird angezeigt.</string>
|
||||
<string name="revanced_skip_autoplay_countdown_title">Autotoplay Countdown überspringen</string>
|
||||
<string name="revanced_skip_autoplay_countdown_summary_on">Ist Autoplay aktiviert, wird das nächste Video sofort abgespielt.</string>
|
||||
<string name="revanced_skip_autoplay_countdown_summary_off">Wenn Autoplay aktiviert ist, wird das nächste Video nach dem Countdown abgespielt.</string>
|
||||
@ -1490,6 +1492,10 @@ Drücken und halten Sie die Schaltfläche Mehr, um den Dialog benutzerdefinierte
|
||||
<string name="revanced_shorts_custom_actions_open_video_title">Zeige geöffnetes Video-Menü</string>
|
||||
<string name="revanced_shorts_custom_actions_open_video_summary_on">Video-Menü wird angezeigt.</string>
|
||||
<string name="revanced_shorts_custom_actions_open_video_summary_off">Video-Menü öffnen ist ausgeblendet.</string>
|
||||
<string name="revanced_shorts_custom_actions_speed_dialog_label">Geschwindigkeitsdialog</string>
|
||||
<string name="revanced_shorts_custom_actions_speed_dialog_title">Menü „Geschwindigkeitsdialog anzeigen“</string>
|
||||
<string name="revanced_shorts_custom_actions_speed_dialog_summary_on">Das Dialogmenü „Geschwindigkeit“ wird angezeigt.</string>
|
||||
<string name="revanced_shorts_custom_actions_speed_dialog_summary_off">Das „Geschwindigkeitsdialogmenü“ ist ausgeblendet.</string>
|
||||
<string name="revanced_shorts_custom_actions_repeat_state_label">Status wiederholen</string>
|
||||
<string name="revanced_shorts_custom_actions_repeat_state_title">Zeige Wiederholungsstatus Menü</string>
|
||||
<string name="revanced_shorts_custom_actions_repeat_state_summary_on">Das Statusmenü wird angezeigt.</string>
|
||||
@ -1594,6 +1600,7 @@ Keine Ränder oben und unten des Spielers."</string>
|
||||
<!-- PreferenceScreen: Video -->
|
||||
<string name="revanced_preference_screen_video_title">Video</string>
|
||||
<!-- PreferenceScreen: Video, PreferenceCategory: Codec -->
|
||||
<string name="revanced_preference_category_codec">Codec</string>
|
||||
<string name="revanced_disable_hdr_video_title">HDR-Video deaktivieren</string>
|
||||
<string name="revanced_disable_hdr_video_summary_on">HDR-Video ist deaktiviert</string>
|
||||
<string name="revanced_disable_hdr_video_summary_off">HDR-Video ist aktiviert</string>
|
||||
@ -1607,6 +1614,7 @@ Keine Ränder oben und unten des Spielers."</string>
|
||||
<string name="revanced_replace_av1_codec_title">Replace software AV1 codec</string>
|
||||
<string name="revanced_replace_av1_codec_summary">Replaces the software AV1 codec with the VP9 codec.</string>
|
||||
<!-- PreferenceScreen: Video, PreferenceCategory: Playback speed -->
|
||||
<string name="revanced_preference_category_playback_speed">Wiedergabegeschwindigkeit</string>
|
||||
<string name="revanced_default_playback_speed_title">Standard Wiedergabegeschwindigkeit</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_title">Remember playback speed changes</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_summary_on">Playback speed changes apply to all videos.</string>
|
||||
@ -1614,6 +1622,7 @@ Keine Ränder oben und unten des Spielers."</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_toast_title">Toast anzeigen</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_toast_summary_on">Beim Ändern der Standard-Wiedergabegeschwindigkeit wird ein Toast angezeigt.</string>
|
||||
<string name="revanced_remember_playback_speed_last_selected_toast_summary_off">Beim Ändern der Standard-Wiedergabegeschwindigkeit wird kein Toast angezeigt.</string>
|
||||
<string name="revanced_default_playback_speed_shorts_title">Standard Wiedergabegeschwindigkeit bei Shorts</string>
|
||||
<string name="revanced_enable_custom_playback_speed_title">Benutzerdefinierte Wiedergabegeschwindigkeit aktivieren</string>
|
||||
<string name="revanced_enable_custom_playback_speed_summary_on">Benutzerdefinierte Wiedergabegeschwindigkeit ist aktiviert</string>
|
||||
<string name="revanced_enable_custom_playback_speed_summary_off">Benutzerdefinierte Wiedergabegeschwindigkeit ist deaktiviert</string>
|
||||
@ -1625,6 +1634,7 @@ Keine Ränder oben und unten des Spielers."</string>
|
||||
<string name="revanced_custom_playback_speeds_invalid">Ungültige benutzerdefinierte Wiedergabegeschwindigkeiten. Auf Standardwerte zurücksetzen.</string>
|
||||
<string name="revanced_custom_playback_speeds_parse_exception">Ungültige benutzerdefinierte Wiedergabegeschwindigkeiten. Auf Standardwerte zurücksetzen.</string>
|
||||
<!-- PreferenceScreen: Video, PreferenceCategory: Video quality -->
|
||||
<string name="revanced_preference_category_video_quality">Videoqualität</string>
|
||||
<string name="revanced_default_video_quality_mobile_title">Standard Videoqualität im Mobilfunk</string>
|
||||
<string name="revanced_default_video_quality_wifi_title">Standard-Videoqualität im Wlan</string>
|
||||
<string name="revanced_remember_video_quality_last_selected_title">Qualitätseinstellungen merken</string>
|
||||
@ -1897,7 +1907,7 @@ Klicken Sie hier, um zu sehen, wie Sie einen API-Schlüssel ausgeben."</string>
|
||||
<string name="revanced_sb_about_api">sponsor.ajay.app</string>
|
||||
<string name="revanced_sb_about_api_sum">Die Daten werden von der SponsorBlock API bereitgestellt. Tippen Sie hier, um mehr zu erfahren und Downloads für andere Plattformen zu sehen</string>
|
||||
<!-- PreferenceScreen: Miscellaneous -->
|
||||
<string name="revanced_preference_screen_misc_title">PreferenceScreen: Sonstiges</string>
|
||||
<string name="revanced_preference_screen_misc_title">Sonstiges</string>
|
||||
<string name="revanced_bypass_url_redirects_title">URL-Weiterleitungen umgehen</string>
|
||||
<string name="revanced_bypass_url_redirects_summary_on">URL-Weiterleitungen werden umgangen.</string>
|
||||
<string name="revanced_bypass_url_redirects_summary_off">URL-Umleitungen werden nicht umgangen.</string>
|
||||
@ -1937,7 +1947,7 @@ Drücke Weiter und deaktiviere Akku-Optimierungen."</string>
|
||||
<string name="revanced_enable_opus_codec_summary">Aktiviere den OPUS-Codec, wenn die Antwort des Players den OPUS-Codec enthält.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Import / Export settings -->
|
||||
<string name="revanced_preference_screen_import_export_title">Einstellungen importieren / exportieren</string>
|
||||
<string name="revanced_preference_screen_import_export_summary">Einstellungen importieren / exportieren</string>
|
||||
<string name="revanced_preference_screen_import_export_summary">Importieren / Exportieren der RVX Einstellungen.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Import / Export settings, PreferenceCategory: Import / Export as file -->
|
||||
<string name="revanced_preference_category_import_export_as_file">Als Datei importieren / exportieren</string>
|
||||
<string name="revanced_extended_settings_export_title">Einstellungen exportieren</string>
|
||||
@ -2043,6 +2053,10 @@ Klicken Sie hier, um weitere Informationen zu sehen."</string>
|
||||
<string name="revanced_preference_screen_patch_information_title">Patch-Informationen</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Informationen über angewandte Patches</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">App Info</string>
|
||||
<string name="revanced_app_name_title">App Name</string>
|
||||
<string name="revanced_app_version_title">App Version</string>
|
||||
<string name="revanced_patched_date_title">Patch Datum</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Andere</string>
|
||||
<string name="revanced_icon_custom">Benutzerdefiniert</string>
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">Προσθήκη στην ουρά</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Προσθήκη στην ουρά και άνοιγμα ουράς</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Προσθήκη στην ουρά και αναπαραγωγή βίντεο</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Προσθήκη στην ουρά και επαναφόρτωση του βίντεο</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Εξωτερικό πρόγραμμα λήψης</string>
|
||||
<string name="revanced_queue_manager_open_queue">Άνοιγμα ουράς</string>
|
||||
<string name="revanced_queue_manager_queue">Ουρά</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Αφαίρεση από την ουρά</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Αφαίρεση από την ουρά και άνοιγμα ουράς</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Αφαίρεση από την ουρά και επαναφόρτωση του βίντεο</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Κατάργηση ουράς</string>
|
||||
<string name="revanced_queue_manager_save_queue">Αποθήκευση ουράς</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Αντί να ανοίξετε ένα εξωτερικό πρόγραμμα λήψης, ανοίξτε το παράθυρο διαχείρισης ουράς.
|
||||
@ -2163,6 +2165,10 @@ Playlists
|
||||
<string name="revanced_preference_screen_patch_information_title">Πληροφορίες τροποποίησης</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Πληροφορίες σχετικά με τις εφαρμοσμένες τροποποιήσεις.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Πληροφορίες εφαρμογής</string>
|
||||
<string name="revanced_app_name_title">Όνομα εφαρμογής</string>
|
||||
<string name="revanced_app_version_title">Έκδοση εφαρμογής</string>
|
||||
<string name="revanced_patched_date_title">Ημερομηνία τροποποίησης</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Άλλα</string>
|
||||
<string name="revanced_icon_custom">Προσαρμοσμένο</string>
|
||||
|
@ -22,11 +22,13 @@ Por favor, descarga %2$s desde el sitio web."</string>
|
||||
<string name="revanced_queue_manager_add_to_queue">Añadir a la cola</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Añadir a la cola y abrir la cola</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Añadir a la cola y reproducir vídeo</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Añadir a la cola y recargar vídeo</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Descargador externo</string>
|
||||
<string name="revanced_queue_manager_open_queue">Abrir cola</string>
|
||||
<string name="revanced_queue_manager_queue">Cola</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Eliminar de la cola</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Eliminar de la cola y abrir la cola</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Eliminar de la cola y recargar vídeo</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Eliminar cola</string>
|
||||
<string name="revanced_queue_manager_save_queue">Guardar cola</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"En lugar de abrir un descargador externo, abre el diálogo del gestor de colas.
|
||||
@ -2134,6 +2136,10 @@ Pulsa aquí para ver más información."</string>
|
||||
<string name="revanced_preference_screen_patch_information_title">Información de parches</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Información sobre los parches aplicados.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Información de la app</string>
|
||||
<string name="revanced_app_name_title">Nombre de la app</string>
|
||||
<string name="revanced_app_version_title">Versión de la app</string>
|
||||
<string name="revanced_patched_date_title">Fecha de parcheado</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Otros</string>
|
||||
<string name="revanced_icon_custom">Personalizado</string>
|
||||
|
@ -22,11 +22,13 @@ Veuillez télécharger %2$s à partir du site web."</string>
|
||||
<string name="revanced_queue_manager_add_to_queue">Ajouter à la file d\'attente</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Ajouter à la file d\'attente et ouvrir la file d\'attente</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Ajouter à la file d\'attente et lire la vidéo</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Ajouter à la file d\'attente et recharger la vidéo</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Téléchargeur externe</string>
|
||||
<string name="revanced_queue_manager_open_queue">Ouvrir la file d\'attente</string>
|
||||
<string name="revanced_queue_manager_queue">File d\'attente</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Retirer de la file d\'attente</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Retirer de la file d\'attente et ouvrir la file d\'attente</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Supprimer de la file d\'attente et recharger la vidéo</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Retirer de la file d\'attente</string>
|
||||
<string name="revanced_queue_manager_save_queue">Enregistrer la file d’attente</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Au lieu d’ouvrir un téléchargeur externe, ouvrez la boîte de dialogue du gestionnaire de file d’attente.
|
||||
@ -2149,6 +2151,10 @@ Cliquez pour plus d'informations."</string>
|
||||
<string name="revanced_preference_screen_patch_information_title">Informations sur les patchs</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Informations sur les patchs appliqués.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Info sur l\'app</string>
|
||||
<string name="revanced_app_name_title">Nom de l\'application</string>
|
||||
<string name="revanced_app_version_title">Version de l\'appli</string>
|
||||
<string name="revanced_patched_date_title">Date du patch</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Autres</string>
|
||||
<string name="revanced_icon_custom">Personnalisé</string>
|
||||
|
@ -22,11 +22,13 @@ Si prega di scaricare %2$s dal sito web."</string>
|
||||
<string name="revanced_queue_manager_add_to_queue">Aggiungi alla coda</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Aggiungi alla coda e aprila</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Aggiungi alla coda e riproduci il video</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Aggiungi alla coda e ricarica il video</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Downloader esterno</string>
|
||||
<string name="revanced_queue_manager_open_queue">Apri la coda</string>
|
||||
<string name="revanced_queue_manager_queue">Coda</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Rimuovi dalla coda</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Rimuovi dalla coda e aprila</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Rimuovi dalla coda e ricarica il video</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Rimuovi la coda</string>
|
||||
<string name="revanced_queue_manager_save_queue">Salva la coda</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Invece di aprire un downloader esterno, apri la finestra di dialogo del gestore delle code.
|
||||
@ -2143,6 +2145,10 @@ Tocca per vedere maggiori informazioni."</string>
|
||||
<string name="revanced_preference_screen_patch_information_title">Informazioni patch</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Informazioni sulle patch applicate.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Informazioni sull\'app</string>
|
||||
<string name="revanced_app_name_title">Nome</string>
|
||||
<string name="revanced_app_version_title">Versione</string>
|
||||
<string name="revanced_patched_date_title">Data e ora della patch</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Altri</string>
|
||||
<string name="revanced_icon_custom">Personalizzata</string>
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">キューに追加</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">キューに追加してキューを開く</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">キューに追加して動画を再生</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">キューに追加して動画を再読み込み</string>
|
||||
<string name="revanced_queue_manager_external_downloader">外部ダウンローダー</string>
|
||||
<string name="revanced_queue_manager_open_queue">キューを開く</string>
|
||||
<string name="revanced_queue_manager_queue">キュー</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">キューから削除</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">キューから削除してキューを開く</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">キューから削除して動画を再読み込み</string>
|
||||
<string name="revanced_queue_manager_remove_queue">キューを削除</string>
|
||||
<string name="revanced_queue_manager_save_queue">キューを保存</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"外部ダウンローダーを開く代わりに、キューマネージャーダイアログを開きます。
|
||||
@ -410,7 +412,7 @@ DeArrow の詳細については、ここをタップしてください。"</str
|
||||
<string name="revanced_change_start_page_entry_shorts">ショート</string>
|
||||
<string name="revanced_change_start_page_entry_sports">スポーツ</string>
|
||||
<string name="revanced_change_start_page_entry_subscriptions">登録チャンネル</string>
|
||||
<string name="revanced_change_start_page_entry_trending">トレンド</string>
|
||||
<string name="revanced_change_start_page_entry_trending">急上昇</string>
|
||||
<string name="revanced_change_start_page_entry_virtual_reality">バーチャル リアリティ</string>
|
||||
<string name="revanced_change_start_page_entry_watch_later">後で見る</string>
|
||||
<string name="revanced_change_start_page_entry_your_clips">クリップ</string>
|
||||
@ -838,9 +840,9 @@ DeArrow の詳細については、ここをタップしてください。"</str
|
||||
<string name="revanced_hide_share_button_title">「共有」ボタンを非表示</string>
|
||||
<string name="revanced_hide_share_button_summary_on">「共有」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_share_button_summary_off">「共有」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shop_button_title">「ショップ」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">「ショップ」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">「ショップ」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shop_button_title">「ショッピング」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shop_button_summary_on">「ショッピング」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shop_button_summary_off">「ショッピング」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_thanks_button_title">「Thanks」ボタンを非表示</string>
|
||||
<string name="revanced_hide_thanks_button_summary_on">「Thanks」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_thanks_button_summary_off">「Thanks」ボタンを非表示にします。</string>
|
||||
@ -1394,9 +1396,9 @@ DeArrow の詳細については、ここをタップしてください。"</str
|
||||
<string name="revanced_hide_shorts_subscribe_button_title">「チャンネル登録」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_subscribe_button_summary_on">「チャンネル登録」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_subscribe_button_summary_off">「チャンネル登録」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_trends_button_title">「トレンド」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_trends_button_summary_on">「トレンド」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_trends_button_summary_off">「トレンド」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_trends_button_title">「急上昇」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_trends_button_summary_on">「急上昇」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_trends_button_summary_off">「急上昇」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_video_title_title">動画のタイトルを非表示</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_on">プレーヤー下部に表示される動画のタイトル名を非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_video_title_summary_off">プレーヤー下部に表示される動画のタイトルを非表示にします。</string>
|
||||
@ -1414,9 +1416,9 @@ DeArrow の詳細については、ここをタップしてください。"</str
|
||||
<string name="revanced_hide_shorts_search_suggestions_button_title">検索候補のボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_button_summary_on">検索候補のボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_search_suggestions_button_summary_off">検索候補のボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_shop_button_title">「ショップ」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_on">「ショップ」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_off">「ショップ」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_shop_button_title">「ショッピング」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_on">「ショッピング」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_shop_button_summary_off">「ショッピング」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_title">「Super Thanks」ボタンを非表示</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_on">「Super Thanks」ボタンを非表示にします。</string>
|
||||
<string name="revanced_hide_shorts_super_thanks_button_summary_off">「Super Thanks」ボタンを非表示にします。</string>
|
||||
@ -2096,6 +2098,10 @@ iOS クライアント選択する場合は、これらの値が必要になる
|
||||
<string name="revanced_preference_screen_patch_information_title">パッチ情報</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">適用されたパッチに関する情報です。</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">アプリ情報</string>
|
||||
<string name="revanced_app_name_title">アプリ名</string>
|
||||
<string name="revanced_app_version_title">アプリバージョン</string>
|
||||
<string name="revanced_patched_date_title">パッチ適用日時</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">その他</string>
|
||||
<string name="revanced_icon_custom">カスタム</string>
|
||||
|
@ -500,7 +500,7 @@ DeArrow에 대해 자세히 알아보려면 여기를 누르세요."</string>
|
||||
<string name="revanced_hide_gray_separator_summary_on">동영상들 사이에서 회색 구분선이 숨겨집니다.</string>
|
||||
<string name="revanced_hide_gray_separator_summary_off">동영상들 사이에서 회색 구분선이 표시됩니다.</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_title">시청 경고 다이얼로그 제거하기</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"다음 동영상을 시청하기 전에 표시되는 시청 경고 다이얼로그를 제거합니다:\n• 연령 제한 동영상\n• 혐오감을 주는 동영상\n• 자살 또는 자해와 관련된 동영상, etc.\n\n이 설정은 다이얼로그를 자동으로 허용하기만 하며 연령 제한(성인인증 절차)을 우회할 수 없습니다."</string>
|
||||
<string name="revanced_remove_viewer_discretion_dialog_summary">"다음 동영상을 시청하기 전에 표시되는 시청 경고 다이얼로그를 제거합니다:\n• 연령 제한 동영상\n• 자살 또는 자해와 관련된 동영상, etc.\n\n이 설정은 다이얼로그를 자동으로 허용하기만 하며 연령 제한(성인인증 절차)을 우회할 수 없습니다."</string>
|
||||
<string name="revanced_change_live_ring_click_action_title">라이브 링 누르기 동작 변경하기</string>
|
||||
<string name="revanced_change_live_ring_click_action_summary_on">"라이브 링이 표시된 채널 아이콘을 누르면 채널 프로필으로 연결됩니다.
|
||||
|
||||
|
@ -22,11 +22,13 @@ Por favor, baixe %2$s do site."</string>
|
||||
<string name="revanced_queue_manager_add_to_queue">Adicionar à fila</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Adicionar à fila e abrir a fila</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Adicionar à fila e reproduzir o vídeo</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Adicionar à fila e recarregar o vídeo</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Download externo</string>
|
||||
<string name="revanced_queue_manager_open_queue">Abrir fila</string>
|
||||
<string name="revanced_queue_manager_queue">Fila</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Remover da lista</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Remover da fila e abrir a fila</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Remover da fila e recarregar vídeo</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Remover fila</string>
|
||||
<string name="revanced_queue_manager_save_queue">Salvar fila</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Em vez de abrir um aplicativo de download externo, abra a caixa de diálogo do gerenciador de filas.
|
||||
@ -53,14 +55,50 @@ Use-o apenas para fins de depuração."</string>
|
||||
<string name="revanced_queue_manager_fetch_succeeded_save">Fila salva com sucesso em \'%s\'.</string>
|
||||
<string name="revanced_language_title">Idioma do RVX</string>
|
||||
<string name="revanced_language_DEFAULT">Idioma do app</string>
|
||||
<string name="revanced_language_CA">"Catalão
|
||||
<small>Català</small>"</string>
|
||||
<string name="revanced_language_CS">"Checo
|
||||
<small>Čeština</small>"</string>
|
||||
<string name="revanced_language_DE">"Alemão
|
||||
<small>Deutsch</small>"</string>
|
||||
<string name="revanced_language_EL">"Grego
|
||||
<small>Ελληνικά</small>"</string>
|
||||
<string name="revanced_language_EN">"Inglês
|
||||
<small>English</small>"</string>
|
||||
<string name="revanced_language_ES">"Espanhol
|
||||
<small>Español</small>"</string>
|
||||
<string name="revanced_language_FR">"Francês
|
||||
<small>Français</small>"</string>
|
||||
<string name="revanced_language_HE">"Hebraico
|
||||
<small>עברי</small>"</string>
|
||||
<string name="revanced_language_IT">"Italiano
|
||||
<small>Italiano</small>"</string>
|
||||
<string name="revanced_language_JA">"Japonês
|
||||
<small>日本語</small>"</string>
|
||||
<string name="revanced_language_KO">"Coreano
|
||||
<small>한국어</small>"</string>
|
||||
<string name="revanced_language_NL">"Holandês
|
||||
<small>Nederlands</small>"</string>
|
||||
<string name="revanced_language_PL">"Polonês
|
||||
<small>Polski</small>"</string>
|
||||
<string name="revanced_language_PT">"Português
|
||||
<small>Português</small>"</string>
|
||||
<string name="revanced_language_RO">"Romeno
|
||||
<small>Română</small>"</string>
|
||||
<string name="revanced_language_RU">"Russo
|
||||
<small>Русский</small>"</string>
|
||||
<string name="revanced_language_SR">"Sérvio
|
||||
<small>Српски</small>"</string>
|
||||
<string name="revanced_language_SV">"Sueco
|
||||
<small>Svenska</small>"</string>
|
||||
<string name="revanced_language_TH">"Tailandês
|
||||
<small>ไทย</small>"</string>
|
||||
<string name="revanced_language_TR">"Turco
|
||||
<small>Türkçe</small>"</string>
|
||||
<string name="revanced_language_UK">"Ucraniano
|
||||
<small>Українська</small>"</string>
|
||||
<string name="revanced_language_ZH">"Chinês
|
||||
<small>中文</small>"</string>
|
||||
<!-- PreferenceScreen: Ads -->
|
||||
<string name="revanced_preference_screen_ads_title">Anúncios</string>
|
||||
<string name="revanced_hide_end_screen_store_banner_title">Ocultar banner da loja na tela final</string>
|
||||
@ -1710,6 +1748,7 @@ Clique para ver como emitir uma chave de API."</string>
|
||||
<string name="revanced_sb_skip_showbutton">Exibir botão de pular</string>
|
||||
<string name="revanced_sb_skip_seekbaronly">Exibir na barra de progresso</string>
|
||||
<string name="revanced_sb_skip_ignore">Desativar</string>
|
||||
<string name="revanced_sb_color_opacity_label">Opacidade:</string>
|
||||
<string name="revanced_sb_color_dot_label">Cor:</string>
|
||||
<string name="revanced_sb_color_changed">Cor alterada.</string>
|
||||
<string name="revanced_sb_color_reset">Redefinir cor.</string>
|
||||
@ -1894,6 +1933,8 @@ Toque no botão continuar e desative as otimizações da bateria."</string>
|
||||
<string name="revanced_spoof_streaming_data_type_entry_android_vr">Android VR</string>
|
||||
<string name="revanced_spoof_streaming_data_type_entry_android_vr_no_auth">"Android VR
|
||||
<small>(Sem autenticação)</small>"</string>
|
||||
<string name="revanced_spoof_streaming_data_type_entry_ios_deprecated">"iOS
|
||||
<small>(Obsoleto)</small>"</string>
|
||||
<string name="revanced_spoof_streaming_data_type_entry_ios_unplugged">"iOS TV
|
||||
<small>(é necessário logar)</small>"</string>
|
||||
<string name="revanced_spoof_streaming_data_side_effects_title">Efeitos colaterais da falsificação</string>
|
||||
@ -1926,6 +1967,7 @@ O AVC tem uma resolução máxima de 1080p, o codec de áudio Opus não está di
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">O cliente usado para buscar dados de streaming é mostrado em Estatísticas para nerds.</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">O cliente usado para buscar dados de streaming está oculto em Estatísticas para nerds.</string>
|
||||
<string name="revanced_spoof_streaming_data_language_title">Idioma padrão de áudio do VR</string>
|
||||
<string name="revanced_spoof_streaming_data_failed_forbidden_suggestion">Você não pode estar logado.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Spoof streaming data, PreferenceCategory: PoToken / VisitorData -->
|
||||
<string name="revanced_preference_category_po_token_visitor_data">PoToken / VisitorData</string>
|
||||
<string name="revanced_spoof_streaming_data_po_token_title">PoToken a ser utilizado</string>
|
||||
@ -1958,6 +2000,10 @@ Clique para ver mais informações."</string>
|
||||
<string name="revanced_preference_screen_patch_information_title">Informações do patch</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Informações sobre as modificações aplicadas.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Informações do aplicativo</string>
|
||||
<string name="revanced_app_name_title">Nome do aplicativo</string>
|
||||
<string name="revanced_app_version_title">Versão do aplicativo</string>
|
||||
<string name="revanced_patched_date_title">Data da atualização</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Outros</string>
|
||||
<string name="revanced_icon_custom">Personalizado</string>
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">Добавить в очередь</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Добавить в очередь и открыть очередь</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Добавить в очередь и посмотреть</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Добавить в очередь и обновить</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Внешний загрузчик</string>
|
||||
<string name="revanced_queue_manager_open_queue">Открыть очередь</string>
|
||||
<string name="revanced_queue_manager_queue">Очередь</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Удалить из очереди</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Удалить из очереди и открыть очередь</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Удалить из очереди и обновить</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Удалить очередь</string>
|
||||
<string name="revanced_queue_manager_save_queue">Сохранить очередь</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Вместо открытия внешнего загрузчика открывается диалог управления очередью.
|
||||
@ -1248,7 +1250,7 @@ Shorts
|
||||
<string name="revanced_overlay_button_play_all_summary">"Коснитесь, чтобы создать список просмотра всех видео из канала.
|
||||
Коснитесь и удерживайте, для отмены.
|
||||
|
||||
Инфо:
|
||||
Информация:
|
||||
• Может не работать в прямых трансляциях."</string>
|
||||
<string name="revanced_overlay_button_play_all_type_title">Сортировка создаваемого списка</string>
|
||||
<string name="revanced_overlay_button_play_all_type_entry_0">Все (сорт. по времени, по возрастанию)</string>
|
||||
@ -2104,7 +2106,7 @@ Shorts
|
||||
<string name="revanced_spoof_streaming_data_type_ios_title">Использовать клиент iOS</string>
|
||||
<string name="revanced_spoof_streaming_data_type_ios_summary_on">"Клиент iOS добавлен к доступным клиентам.
|
||||
|
||||
ВНИМАНИЕ: Клиент iOS устаревший. Любые проблемы, возникающие при его использовании, на свой страх и риск."</string>
|
||||
ПРЕДУПРЕЖДЕНИЕ: Клиент iOS устаревший. Любые проблемы, возникающие при его использовании, на свой страх и риск."</string>
|
||||
<string name="revanced_spoof_streaming_data_type_ios_summary_off">Клиент iOS не добавлен к доступным клиентам.</string>
|
||||
<string name="revanced_spoof_streaming_data_type_ios_user_dialog_message">"При запросе конечных точек YouTube API с помощью iOS требуются токены Auth, выданные устройством iOS, и токены PoToken, выданные iOSGuard.
|
||||
|
||||
@ -2165,6 +2167,10 @@ Shorts
|
||||
<string name="revanced_preference_screen_patch_information_title">Информация о патчах</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Информация о примененных патчах.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">О приложении</string>
|
||||
<string name="revanced_app_name_title">Имя приложения</string>
|
||||
<string name="revanced_app_version_title">Версия приложения</string>
|
||||
<string name="revanced_patched_date_title">Дата применения патчей</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Другие</string>
|
||||
<string name="revanced_icon_custom">Пользовательский</string>
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">Додати до черги</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Додати до черги й відкрити чергу</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Додати до черги й відтворити відео</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Додати до черги та перевантажити відео</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Зовнішній завантажувач</string>
|
||||
<string name="revanced_queue_manager_open_queue">Відкрити чергу</string>
|
||||
<string name="revanced_queue_manager_queue">Черга</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Видалити з черги</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Вилучити з черги й відкрити чергу</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Видалити з черги та перевантажити відео</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Вилучити чергу</string>
|
||||
<string name="revanced_queue_manager_save_queue">Зберегти чергу</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Замість відкривання зовнішнього завантажувача відкриває діалог керування чергою.
|
||||
@ -2114,7 +2116,7 @@ AVC має максимальну роздільну здатність 1080p,
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_on">Клієнт, що використовується для отримання даних трансляції показується у Статистика для сисадмінів.</string>
|
||||
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary_off">Клієнт, що використовується для отримання даних трансляції приховано у Статистика для сисадмінів.</string>
|
||||
<string name="revanced_spoof_streaming_data_language_title">Мова звукової доріжки для VR</string>
|
||||
<string name="revanced_spoof_streaming_data_failed_forbidden">Не вдалося отримати якісь трансляції клієнта.</string>
|
||||
<string name="revanced_spoof_streaming_data_failed_forbidden">Не вдалося отримати які-небудь трансляції клієнта.</string>
|
||||
<string name="revanced_spoof_streaming_data_failed_forbidden_suggestion">Не можливо авторизуватися.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Spoof streaming data, PreferenceCategory: PoToken / VisitorData -->
|
||||
<string name="revanced_preference_category_po_token_visitor_data">PoToken / VisitorData</string>
|
||||
@ -2148,6 +2150,10 @@ AVC має максимальну роздільну здатність 1080p,
|
||||
<string name="revanced_preference_screen_patch_information_title">Інформація про патчі</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Інформація про застосовані патчі.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Інформація про додаток</string>
|
||||
<string name="revanced_app_name_title">Назва додатка</string>
|
||||
<string name="revanced_app_version_title">Версія додатка</string>
|
||||
<string name="revanced_patched_date_title">Дата пропатчування</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Інше</string>
|
||||
<string name="revanced_icon_custom">Користувацька</string>
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">Thêm vào hàng chờ</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">Thêm vào hàng chờ và xem hàng chờ</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">Thêm vào hàng chờ và phát video</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">Thêm vào hàng chờ và tải lại video</string>
|
||||
<string name="revanced_queue_manager_external_downloader">Trình tải xuống bên ngoài</string>
|
||||
<string name="revanced_queue_manager_open_queue">Xem hàng chờ</string>
|
||||
<string name="revanced_queue_manager_queue">Hàng chờ</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">Xóa khỏi hàng chờ</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">Xóa khỏi hàng chờ và xem hàng chờ</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">Xoá khỏi hàng chờ và tải lại video</string>
|
||||
<string name="revanced_queue_manager_remove_queue">Xoá hàng chờ</string>
|
||||
<string name="revanced_queue_manager_save_queue">Lưu hàng chờ</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"Thay vì mở trình tải xuống bên ngoài, khi tương tác sẽ mở hộp thoại quản lý hàng chờ.
|
||||
@ -2151,6 +2153,10 @@ Nhấp vào đây để biết thêm chi tiết."</string>
|
||||
<string name="revanced_preference_screen_patch_information_title">Thông tin bản vá</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">Thông tin về các bản vá được áp dụng.</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">Thông tin ứng dụng</string>
|
||||
<string name="revanced_app_name_title">Tên ứng dụng</string>
|
||||
<string name="revanced_app_version_title">Phiên bản ứng dụng</string>
|
||||
<string name="revanced_patched_date_title">Ngày vá</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">Khác</string>
|
||||
<string name="revanced_icon_custom">Tùy chỉnh</string>
|
||||
|
@ -22,11 +22,13 @@
|
||||
<string name="revanced_queue_manager_add_to_queue">加入佇列清單</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_open_queue">加到佇列並打開佇列</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_play_video">加入佇列並播放影片</string>
|
||||
<string name="revanced_queue_manager_add_to_queue_and_reload_video">加入佇列並重新載入影片</string>
|
||||
<string name="revanced_queue_manager_external_downloader">外部下載器</string>
|
||||
<string name="revanced_queue_manager_open_queue">開啟佇列</string>
|
||||
<string name="revanced_queue_manager_queue">佇列</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue">從佇列中移除</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_open_queue">從佇列中移除並打開佇列</string>
|
||||
<string name="revanced_queue_manager_remove_from_queue_and_reload_video">從佇列移除並重新載入影片</string>
|
||||
<string name="revanced_queue_manager_remove_queue">移除佇列</string>
|
||||
<string name="revanced_queue_manager_save_queue">儲存佇列</string>
|
||||
<string name="revanced_queue_manager_user_dialog_message">"不要開啟外部下載器,而是開啟佇列管理器對話方塊。
|
||||
@ -506,15 +508,15 @@
|
||||
<string name="revanced_change_form_factor_entry_4">平板</string>
|
||||
<string name="revanced_change_form_factor_entry_5">平板電腦 (最少 600 dp)</string>
|
||||
<string name="revanced_change_form_factor_entry_6">車用</string>
|
||||
<string name="revanced_change_form_factor_user_dialog_message">"改變包括:
|
||||
<string name="revanced_change_form_factor_user_dialog_message">"變更內容包括:
|
||||
|
||||
平板佈局
|
||||
• 社群貼文被隱藏。
|
||||
• 隱藏社群貼文。
|
||||
|
||||
車用佈局
|
||||
• 常規播放器中的短影音開啟。
|
||||
• 資訊流依主題和頻道進行組織。
|
||||
• 關閉「偽裝串流數據」時無法開啟影片說明。"</string>
|
||||
• 一般播放器中的短影音開啟。
|
||||
• 動態消息按主題和頻道分類。
|
||||
• 關閉「偽裝串流數據」時無法開啟影片描述。"</string>
|
||||
<string name="revanced_disable_layout_updates_title">禁用佈局更新</string>
|
||||
<string name="revanced_disable_layout_updates_summary_on">伺服器不會更新佈局。</string>
|
||||
<string name="revanced_disable_layout_updates_summary_off">佈局將由伺服器更新。</string>
|
||||
@ -1362,9 +1364,9 @@
|
||||
<string name="revanced_expand_video_description_summary_off">手動展開影片描述</string>
|
||||
<!-- PreferenceScreen: Shorts -->
|
||||
<string name="revanced_preference_screen_shorts_title">短影音</string>
|
||||
<string name="revanced_disable_shorts_background_playback_title">停用 短影音 後台播放</string>
|
||||
<string name="revanced_disable_shorts_background_playback_summary_on">短影音 後台播放已停用。</string>
|
||||
<string name="revanced_disable_shorts_background_playback_summary_off">短影音 後台播放已啟用。</string>
|
||||
<string name="revanced_disable_shorts_background_playback_title">停用短影音背景播放</string>
|
||||
<string name="revanced_disable_shorts_background_playback_summary_on">短影音背景播放已停用。</string>
|
||||
<string name="revanced_disable_shorts_background_playback_summary_off">短影音背景播放已啟用。</string>
|
||||
<string name="revanced_disable_resuming_shorts_player_title">停用恢復短影音播放器</string>
|
||||
<string name="revanced_disable_resuming_shorts_player_summary_on">短影音播放器在應用程式啟動時不會恢復播放。</string>
|
||||
<string name="revanced_disable_resuming_shorts_player_summary_off">短影音播放器在應用程式啟動時會恢復播放。</string>
|
||||
@ -1396,15 +1398,15 @@
|
||||
<string name="revanced_hide_shorts_shelf_history_summary_on">在觀看歷史中隱藏</string>
|
||||
<string name="revanced_hide_shorts_shelf_history_summary_off">在觀看歷史中顯示</string>
|
||||
<!-- PreferenceScreen: Shorts, PreferenceCategory: Experimental flags -->
|
||||
<string name="revanced_change_shorts_background_repeat_state_title">變更 短影音背景重複狀態</string>
|
||||
<string name="revanced_change_shorts_repeat_state_title">更改短影音重複播放狀態</string>
|
||||
<string name="revanced_change_shorts_background_repeat_state_title">變更短影音背景重複狀態</string>
|
||||
<string name="revanced_change_shorts_repeat_state_title">變更短影音重複播放狀態</string>
|
||||
<string name="revanced_change_shorts_repeat_state_entry_auto_play">自動播放</string>
|
||||
<string name="revanced_change_shorts_repeat_state_entry_default">預設</string>
|
||||
<string name="revanced_change_shorts_repeat_state_entry_pause">暫停</string>
|
||||
<string name="revanced_change_shorts_repeat_state_entry_repeat">重複播放</string>
|
||||
<string name="revanced_open_shorts_in_regular_player_title">在一般播放器中開啟 Shorts</string>
|
||||
<string name="revanced_open_shorts_in_regular_player_summary_on">在一般播放器中開啟 Shorts。</string>
|
||||
<string name="revanced_open_shorts_in_regular_player_summary_off">不要在普通播放器中開啟 Shorts。</string>
|
||||
<string name="revanced_open_shorts_in_regular_player_title">在一般播放器中開啟短影音</string>
|
||||
<string name="revanced_open_shorts_in_regular_player_summary_on">在一般播放器中開啟短影音。</string>
|
||||
<string name="revanced_open_shorts_in_regular_player_summary_off">不要在一般播放器中開啟短影音。</string>
|
||||
<!-- PreferenceScreen: Shorts, PreferenceCategory: Shorts, PreferenceScreen: Shorts player -->
|
||||
<string name="revanced_preference_screen_shorts_player_title">短影音播放器</string>
|
||||
<string name="revanced_preference_screen_shorts_player_summary">隱藏或顯示短影音播放器中的組件。</string>
|
||||
@ -2139,6 +2141,10 @@ AVC 的最大解析度為 1080p,Opus 音訊編解碼器不可用,影片播
|
||||
<string name="revanced_preference_screen_patch_information_title">補丁訊息</string>
|
||||
<string name="revanced_preference_screen_patch_information_summary">已應用補丁的訊息</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: App info -->
|
||||
<string name="revanced_preference_category_app_info">應用程式資訊</string>
|
||||
<string name="revanced_app_name_title">應用程式名稱</string>
|
||||
<string name="revanced_app_version_title">應用程式版本</string>
|
||||
<string name="revanced_patched_date_title">修補日期</string>
|
||||
<!-- PreferenceScreen: Miscellaneous, PreferenceCategory: Miscellaneous, PreferenceScreen: Patch information, PreferenceCategory: Others -->
|
||||
<string name="revanced_preference_category_others">其他</string>
|
||||
<string name="revanced_icon_custom">自訂</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user